Enhance the double buffering concept.
[apps/native/widget/widget.git] / src / virtual_window.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define _GNU_SOURCE
18
19 #include <Elementary.h>
20 #include <string.h>
21 #include <Ecore_Evas.h>
22 #include <Ecore_X.h>
23 #include <Evas.h>
24 #include <dlfcn.h>
25 #include <Eina.h>
26
27 #include <X11/Xlib.h>
28
29 #include <dlog.h>
30 #include <dynamicbox_errno.h>
31 #include <dynamicbox_service.h>
32 #include <dynamicbox_conf.h>
33 #include <dynamicbox_buffer.h>
34
35 #include "dynamicbox.h"
36 #include "debug.h"
37
38 #define IS_GBAR 1
39
40 #define PUBLIC __attribute__((visibility("default")))
41 #define DBOX_WIN_TAG "dynamic,box,win"
42
43 #define DBOX_DEFAULT_WIDTH 1
44 #define DBOX_DEFAULT_HEIGHT 1
45 #define GL_ENGINE "opengl_x11"
46
47 static struct static_info {
48     Ecore_Evas *(*alloc_canvas)(int w, int h, void *(*a)(void *data, int size), void (*f)(void *data, void *ptr), void *data);
49     Ecore_Evas *(*alloc_canvas_with_stride)(int w, int h, void *(*a)(void *data, int size, int *stride, int *bpp), void (*f)(void *data, void *ptr), void *data);
50     Ecore_Evas *(*alloc_canvas_with_pixmap)(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h, Ecore_X_Pixmap (*alloc_cb)(void *data, Ecore_X_Window parent, int w, int h, int depth), void (*free_cb)(void *data, Ecore_X_Pixmap pixmap), void *data);
51 } s_info = {
52     .alloc_canvas = NULL,
53     .alloc_canvas_with_stride = NULL,
54     .alloc_canvas_with_pixmap = NULL,
55 };
56
57 /**
58  * @brief
59  * Abstracted Data Type of Virtual Window
60  */
61 typedef struct virtual_window_info {
62     char *id; /**< Identification */
63     dynamicbox_buffer_h handle; /**< Livebox buffer handle */
64     enum win_type {
65         VWIN_SW_BUF = 0x00, /**< S/W buffer */
66         VWIN_GEM    = 0x01, /**< GEM buffer */
67         VWIN_PIXMAP = 0x02, /**< PIXMAP */
68         VWIN_ERROR  = 0x03  /**< Unknown */
69     } type;
70     Ecore_Evas *ee;
71     Evas *e;
72     int is_gbar;
73     int deleted;
74     int w;
75     int h;
76     unsigned int *resource_array;
77     int resource_cnt;
78
79     unsigned int front_resource_id;
80 } *vwin_info_t;
81
82 static inline Evas_Object *get_highlighted_object(Evas_Object *obj)
83 {
84     Evas_Object *o, *ho;
85
86     o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
87     if (!o) return NULL;
88
89     ho = evas_object_data_get(o, "_elm_access_target");
90     return ho;
91 }
92
93 /**
94  * @note
95  * Every user event (mouse) on the buffer will be passed via this event callback
96  */
97 static int event_handler_cb(dynamicbox_buffer_h handler, struct dynamicbox_buffer_event_data *event_info, void *data)
98 {
99     vwin_info_t info = data;
100     Elm_Access_Action_Info action_info;
101     Elm_Access_Action_Type action_type;
102     int ret = 0;
103     Evas_Object *parent_elm;
104     KeySym *key_symbol;
105     unsigned int flags = 0;
106
107     if (!info->handle) {
108         /* Just ignore this event */
109         return 0;
110     }
111
112     /**
113      * @note
114      * Feed up events
115      */
116     switch (event_info->type) {
117         case DBOX_BUFFER_EVENT_ON_HOLD:
118             flags = evas_event_default_flags_get(info->e);
119             flags |= EVAS_EVENT_FLAG_ON_HOLD;
120             evas_event_default_flags_set(info->e, flags);
121             break;
122         case DBOX_BUFFER_EVENT_OFF_HOLD:
123             flags = evas_event_default_flags_get(info->e);
124             flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
125             evas_event_default_flags_set(info->e, flags);
126             break;
127         case DBOX_BUFFER_EVENT_ON_SCROLL:
128             flags = evas_event_default_flags_get(info->e);
129             flags |= EVAS_EVENT_FLAG_ON_SCROLL;
130             evas_event_default_flags_set(info->e, flags);
131             break;
132         case DBOX_BUFFER_EVENT_OFF_SCROLL:
133             flags = evas_event_default_flags_get(info->e);
134             flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
135             evas_event_default_flags_set(info->e, flags);
136             break;
137         case DBOX_BUFFER_EVENT_ENTER:
138             evas_event_feed_mouse_in(info->e, event_info->timestamp * 1000, NULL);
139             break;
140         case DBOX_BUFFER_EVENT_LEAVE:
141             evas_event_feed_mouse_out(info->e, event_info->timestamp * 1000, NULL);
142             break;
143         case DBOX_BUFFER_EVENT_DOWN:
144             /**
145              * @note
146              * Before processing the DOWN event,
147              * Reset the evas event flags regarding ON_HOLD option.
148              * It can be re-enabled while processing down-move-up events.
149              */
150             flags = evas_event_default_flags_get(info->e);
151             flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
152             flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
153             evas_event_default_flags_set(info->e, flags);
154             /**
155              * @note
156              * Calculate the event occurred X & Y on the buffer
157              */
158             evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, event_info->timestamp * 1000, NULL);
159             evas_event_feed_mouse_down(info->e, 1, EVAS_BUTTON_NONE, event_info->timestamp * 1000, NULL); /* + 0.2f just for fake event */
160             break;
161         case DBOX_BUFFER_EVENT_MOVE:
162             /**
163              * @note
164              * Calculate the event occurred X & Y on the buffer
165              */
166             evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, event_info->timestamp * 1000, NULL);
167             break;
168         case DBOX_BUFFER_EVENT_UP:
169             evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, event_info->timestamp * 1000, NULL);
170             evas_event_feed_mouse_up(info->e, 1, EVAS_BUTTON_NONE, event_info->timestamp * 1000, NULL);
171             /**
172              * @note
173              * We have to keep the event flags, so we should not clear them from here.
174              * Sometimes, asynchronously callable Callbacks can refer the evas event flags after up event.
175              * so if we reset them from here, those kind of callbacks will fails to do their job properly.
176              */
177             break;
178         case DBOX_BUFFER_EVENT_ACCESS_HIGHLIGHT:
179             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
180             if (!parent_elm) {
181                 ret = DBOX_ACCESS_STATUS_ERROR;
182                 break;
183             }
184             memset(&action_info, 0, sizeof(action_info));
185             action_type = ELM_ACCESS_ACTION_HIGHLIGHT;
186             /**
187              * @note
188              * Calculate the event occurred X & Y on the buffer
189              */
190             action_info.x = event_info->info.access.x;
191             action_info.y = event_info->info.access.y;
192             ret = elm_access_action(parent_elm, action_type, &action_info);
193             if (ret == EINA_TRUE) {
194                 if (!get_highlighted_object(parent_elm)) {
195                     ErrPrint("Highlighted object is not found\n");
196                     ret = DBOX_ACCESS_STATUS_ERROR;
197                 } else {
198                     DbgPrint("Highlighted object is found\n");
199                     ret = DBOX_ACCESS_STATUS_DONE;
200                 }
201             } else {
202                 ErrPrint("Action error\n");
203                 ret = DBOX_ACCESS_STATUS_ERROR;
204             }
205             break;
206         case DBOX_BUFFER_EVENT_ACCESS_HIGHLIGHT_NEXT:
207             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
208             if (!parent_elm) {
209                 ret = DBOX_ACCESS_STATUS_ERROR;
210                 break;
211             }
212             memset(&action_info, 0, sizeof(action_info));
213             action_type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
214             action_info.highlight_cycle = EINA_FALSE;
215             ret = elm_access_action(parent_elm, action_type, &action_info);
216             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_LAST : DBOX_ACCESS_STATUS_DONE;
217             break;
218         case DBOX_BUFFER_EVENT_ACCESS_HIGHLIGHT_PREV:
219             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
220             if (!parent_elm) {
221                 ret = DBOX_ACCESS_STATUS_ERROR;
222                 break;
223             }
224             memset(&action_info, 0, sizeof(action_info));
225             action_type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
226             action_info.highlight_cycle = EINA_FALSE;
227             ret = elm_access_action(parent_elm, action_type, &action_info);
228             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_FIRST : DBOX_ACCESS_STATUS_DONE;
229             break;
230         case DBOX_BUFFER_EVENT_ACCESS_ACTIVATE:
231             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
232             if (!parent_elm) {
233                 ret = DBOX_ACCESS_STATUS_ERROR;
234                 break;
235             }
236             memset(&action_info, 0, sizeof(action_info));
237             action_type = ELM_ACCESS_ACTION_ACTIVATE;
238             ret = elm_access_action(parent_elm, action_type, &action_info);
239             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
240             break;
241         case DBOX_BUFFER_EVENT_ACCESS_ACTION_UP:
242             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
243             if (!parent_elm) {
244                 ret = DBOX_ACCESS_STATUS_ERROR;
245                 break;
246             }
247             memset(&action_info, 0, sizeof(action_info));
248             action_type = ELM_ACCESS_ACTION_UP;
249             ret = elm_access_action(parent_elm, action_type, &action_info);
250             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
251             break;
252         case DBOX_BUFFER_EVENT_ACCESS_ACTION_DOWN:
253             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
254             if (!parent_elm) {
255                 ret = DBOX_ACCESS_STATUS_ERROR;
256                 break;
257             }
258             memset(&action_info, 0, sizeof(action_info));
259             action_type = ELM_ACCESS_ACTION_DOWN;
260             ret = elm_access_action(parent_elm, action_type, &action_info);
261             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
262             break;
263         case DBOX_BUFFER_EVENT_ACCESS_SCROLL_UP:
264             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
265             if (!parent_elm) {
266                 ret = DBOX_ACCESS_STATUS_ERROR;
267                 break;
268             }
269             memset(&action_info, 0, sizeof(action_info));
270             action_type = ELM_ACCESS_ACTION_SCROLL;
271             action_info.x = event_info->info.access.x;
272             action_info.y = event_info->info.access.y;
273             action_info.mouse_type = event_info->info.access.mouse_type;
274             ret = elm_access_action(parent_elm, action_type, &action_info);
275             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
276             break;
277         case DBOX_BUFFER_EVENT_ACCESS_SCROLL_MOVE:
278             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
279             if (!parent_elm) {
280                 ret = DBOX_ACCESS_STATUS_ERROR;
281                 break;
282             }
283             memset(&action_info, 0, sizeof(action_info));
284             action_type = ELM_ACCESS_ACTION_SCROLL;
285             action_info.x = event_info->info.access.x;
286             action_info.y = event_info->info.access.y;
287             action_info.mouse_type = event_info->info.access.mouse_type;
288             ret = elm_access_action(parent_elm, action_type, &action_info);
289             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
290             break;
291         case DBOX_BUFFER_EVENT_ACCESS_SCROLL_DOWN:
292             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
293             if (!parent_elm) {
294                 ret = DBOX_ACCESS_STATUS_ERROR;
295                 break;
296             }
297             memset(&action_info, 0, sizeof(action_info));
298             action_type = ELM_ACCESS_ACTION_SCROLL;
299             action_info.x = event_info->info.access.x;
300             action_info.y = event_info->info.access.y;
301             action_info.mouse_type = event_info->info.access.mouse_type;
302             ret = elm_access_action(parent_elm, action_type, &action_info);
303             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
304             break;
305         case DBOX_BUFFER_EVENT_ACCESS_UNHIGHLIGHT:
306             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
307             if (!parent_elm) {
308                 ret = DBOX_ACCESS_STATUS_ERROR;
309                 break;
310             }
311             memset(&action_info, 0, sizeof(action_info));
312             action_type = ELM_ACCESS_ACTION_UNHIGHLIGHT;
313             ret = elm_access_action(parent_elm, action_type, &action_info);
314             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
315             break;
316         case DBOX_BUFFER_EVENT_ACCESS_VALUE_CHANGE:
317             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
318             if (!parent_elm) {
319                 ret = DBOX_ACCESS_STATUS_ERROR;
320                 break;
321             }
322             memset(&action_info, 0, sizeof(action_info));
323             action_type = ELM_ACCESS_ACTION_VALUE_CHANGE;
324             action_info.x = event_info->info.access.x;
325             action_info.y = event_info->info.access.y;
326             action_info.mouse_type = event_info->info.access.mouse_type;
327             ret = elm_access_action(parent_elm, action_type, &action_info);
328             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
329             break;
330         case DBOX_BUFFER_EVENT_ACCESS_MOUSE:
331             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
332             if (!parent_elm) {
333                 ret = DBOX_ACCESS_STATUS_ERROR;
334                 break;
335             }
336             memset(&action_info, 0, sizeof(action_info));
337             action_type = ELM_ACCESS_ACTION_MOUSE;
338             action_info.x = event_info->info.access.x;
339             action_info.y = event_info->info.access.y;
340             action_info.mouse_type = event_info->info.access.mouse_type;
341             ret = elm_access_action(parent_elm, action_type, &action_info);
342             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
343             break;
344         case DBOX_BUFFER_EVENT_ACCESS_BACK:
345             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
346             if (!parent_elm) {
347                 ret = DBOX_ACCESS_STATUS_ERROR;
348                 break;
349             }
350             memset(&action_info, 0, sizeof(action_info));
351             action_type = ELM_ACCESS_ACTION_BACK;
352             action_info.x = event_info->info.access.x;
353             action_info.y = event_info->info.access.y;
354             action_info.mouse_type = event_info->info.access.mouse_type;
355             ret = elm_access_action(parent_elm, action_type, &action_info);
356             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
357             break;
358         case DBOX_BUFFER_EVENT_ACCESS_OVER:
359             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
360             if (!parent_elm) {
361                 ret = DBOX_ACCESS_STATUS_ERROR;
362                 break;
363             }
364             memset(&action_info, 0, sizeof(action_info));
365             action_type = ELM_ACCESS_ACTION_OVER;
366             action_info.x = event_info->info.access.x;
367             action_info.y = event_info->info.access.y;
368             action_info.mouse_type = event_info->info.access.mouse_type;
369             ret = elm_access_action(parent_elm, action_type, &action_info);
370             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
371             break;
372         case DBOX_BUFFER_EVENT_ACCESS_READ:
373             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
374             if (!parent_elm) {
375                 ret = DBOX_ACCESS_STATUS_ERROR;
376                 break;
377             }
378             memset(&action_info, 0, sizeof(action_info));
379             action_type = ELM_ACCESS_ACTION_READ;
380             action_info.x = event_info->info.access.x;
381             action_info.y = event_info->info.access.y;
382             action_info.mouse_type = event_info->info.access.mouse_type;
383             ret = elm_access_action(parent_elm, action_type, &action_info);
384             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
385             break;
386         case DBOX_BUFFER_EVENT_ACCESS_ENABLE:
387             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
388             if (!parent_elm) {
389                 ret = DBOX_ACCESS_STATUS_ERROR;
390                 break;
391             }
392             memset(&action_info, 0, sizeof(action_info));
393             action_type = ELM_ACCESS_ACTION_ENABLE;
394             action_info.x = event_info->info.access.x;
395             action_info.y = event_info->info.access.y;
396             action_info.mouse_type = event_info->info.access.mouse_type;
397             ret = elm_access_action(parent_elm, action_type, &action_info);
398             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
399             break;
400         case DBOX_BUFFER_EVENT_ACCESS_DISABLE:
401             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
402             if (!parent_elm) {
403                 ret = DBOX_ACCESS_STATUS_ERROR;
404                 break;
405             }
406             memset(&action_info, 0, sizeof(action_info));
407             action_type = ELM_ACCESS_ACTION_DISABLE;
408             action_info.x = event_info->info.access.x;
409             action_info.y = event_info->info.access.y;
410             action_info.mouse_type = event_info->info.access.mouse_type;
411             ret = elm_access_action(parent_elm, action_type, &action_info);
412             ret = (ret == EINA_FALSE) ? DBOX_ACCESS_STATUS_ERROR : DBOX_ACCESS_STATUS_DONE;
413             break;
414         case DBOX_BUFFER_EVENT_KEY_DOWN:
415             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
416             if (!parent_elm) {
417                 ret = DBOX_ACCESS_STATUS_ERROR;
418                 break;
419             }
420
421             key_symbol = XGetKeyboardMapping(ecore_x_display_get(), event_info->info.keycode, 1, &ret);
422             if (key_symbol) {
423                 char *key_name;
424                 char *key_string;
425
426                 key_string = XKeysymToString(*key_symbol);
427                 key_name = XKeysymToString(*key_symbol);
428                 DbgPrint("Key symbol: %s, name: %s\n", key_string, key_name);
429                 XFree(key_symbol);
430                 XFree(key_name);
431                 XFree(key_string);
432             }
433             ret = DBOX_KEY_STATUS_ERROR;
434             break;
435         case DBOX_BUFFER_EVENT_KEY_UP:
436             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
437             if (!parent_elm) {
438                 ret = DBOX_ACCESS_STATUS_ERROR;
439                 break;
440             }
441
442             key_symbol = XGetKeyboardMapping(ecore_x_display_get(), event_info->info.keycode, 1, &ret);
443             if (key_symbol) {
444                 char *key_name;
445                 char *key_string;
446
447                 key_string = XKeysymToString(*key_symbol);
448                 key_name = XKeysymToString(*key_symbol);
449                 DbgPrint("Key symbol: %s, name: %s\n", key_string, key_name);
450                 XFree(key_symbol);
451                 XFree(key_name);
452                 XFree(key_string);
453             }
454             ret = DBOX_KEY_STATUS_ERROR;
455             break;
456         case DBOX_BUFFER_EVENT_KEY_FOCUS_IN:
457             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
458             if (!parent_elm) {
459                 ret = DBOX_ACCESS_STATUS_ERROR;
460                 break;
461             }
462
463             key_symbol = XGetKeyboardMapping(ecore_x_display_get(), event_info->info.keycode, 1, &ret);
464             if (key_symbol) {
465                 char *key_name;
466                 char *key_string;
467
468                 key_string = XKeysymToString(*key_symbol);
469                 key_name = XKeysymToString(*key_symbol);
470                 DbgPrint("Key symbol: %s, name: %s\n", key_string, key_name);
471                 XFree(key_symbol);
472                 XFree(key_name);
473                 XFree(key_string);
474             }
475             ret = DBOX_KEY_STATUS_ERROR;
476             break;
477         case DBOX_BUFFER_EVENT_KEY_FOCUS_OUT:
478             parent_elm = ecore_evas_data_get(info->ee, DBOX_WIN_TAG);
479             if (!parent_elm) {
480                 ret = DBOX_ACCESS_STATUS_ERROR;
481                 break;
482             }
483
484             key_symbol = XGetKeyboardMapping(ecore_x_display_get(), event_info->info.keycode, 1, &ret);
485             if (key_symbol) {
486                 char *key_name;
487                 char *key_string;
488
489                 key_string = XKeysymToString(*key_symbol);
490                 key_name = XKeysymToString(*key_symbol);
491                 DbgPrint("Key symbol: %s, name: %s\n", key_string, key_name);
492                 XFree(key_symbol);
493                 XFree(key_name);
494                 XFree(key_string);
495             }
496             ret = DBOX_KEY_STATUS_ERROR;
497             break;
498         default:
499             DbgPrint("Unhandled buffer event (%d)\n", event_info->type);
500             break;
501     }
502
503     return ret;
504 }
505
506 /**
507  * @note
508  * This callback can be called twice (or more) to get a several pixmaps
509  * Acquired pixmaps are used for double/tripple buffering for canvas
510  */
511 static Ecore_X_Pixmap alloc_pixmap_cb(void *data, Ecore_X_Window parent, int w, int h, int depth)
512 {
513     vwin_info_t info = data;
514     Ecore_X_Pixmap pixmap;
515
516     if (!info->handle) {
517         ErrPrint("Invalid handle\n");
518         return 0u;
519     }
520
521     info->w = w;
522     info->h = h;
523     DbgPrint("Size of ee is updated: %dx%d - %d (info: %p)\n", info->w, info->h, depth, info);
524     depth >>= 3;
525
526     if (dynamicbox_resource_id(info->handle, DBOX_PRIMARY_BUFFER) == 0u) {
527         /**
528          * @note
529          * Need to allocate a primary buffer
530          */
531         dynamicbox_acquire_buffer(info->handle, DBOX_PRIMARY_BUFFER, info->w, info->h, depth);
532         if (!info->handle) {
533             ErrPrint("Failed to get the buffer\n");
534             return 0u;
535         }
536
537         pixmap = (Ecore_X_Pixmap)dynamicbox_resource_id(info->handle, DBOX_PRIMARY_BUFFER);
538     } else if (DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT > 0) {
539         int idx;
540
541         if (!info->resource_array) {
542             info->resource_array = calloc(DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT, sizeof(*info->resource_array));
543             if (!info->resource_array) {
544                 ErrPrint("Out of memory: %s\n", strerror(errno));
545                 return 0u;
546             }
547
548             idx = 0;
549         } else {
550             for (idx = 0; idx < DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT; idx++) {
551                 if (info->resource_array[idx] == 0u) {
552                     break;
553                 }
554             }
555
556             if (idx == DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT) {
557                 ErrPrint("Out of index: %d\n", idx);
558                 return 0u;
559             }
560         }
561
562         if (dynamicbox_acquire_buffer(info->handle, idx, info->w, info->h, depth) < 0) {
563             ErrPrint("Failed to acquire a buffer for %d\n", idx);
564             return 0u;
565         }
566
567         info->resource_array[idx] = dynamicbox_resource_id(info->handle, idx);
568         if (info->resource_array[idx] == 0u) {
569             ErrPrint("Failed to allocate pixmap\n");
570         }
571
572         DbgPrint("Allocated index: %d/%d - %u\n", idx, DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT, info->resource_array[idx]);
573         pixmap = info->resource_array[idx];
574     }
575
576     /**
577      * Acquire a buffer for canvas.
578      */
579     info->type = VWIN_PIXMAP;
580     info->resource_cnt += !!pixmap;
581     return pixmap;
582 }
583
584 static void free_pixmap_cb(void *data, Ecore_X_Pixmap pixmap)
585 {
586     vwin_info_t info = data;
587
588     if (!info->handle) {
589         return;
590     }
591
592     if (info->type != VWIN_PIXMAP) {
593         ErrPrint("Impossible\n");
594     }
595
596     if (dynamicbox_resource_id(info->handle, DBOX_PRIMARY_BUFFER) == pixmap) {
597         if (dynamicbox_release_buffer(info->handle, DBOX_PRIMARY_BUFFER) < 0) {
598             DbgPrint("Failed to release buffer\n");
599         }
600         info->resource_cnt--;
601     } else {
602         int idx;
603
604         for (idx = 0; idx < DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT; idx++) {
605             /**
606              * @note
607              * Find a index to release it
608              */
609             if (info->resource_array[idx] == pixmap) {
610                 if (dynamicbox_release_buffer(info->handle, idx) < 0) {
611                     DbgPrint("Failed to release buffer\n");
612                 }
613                 info->resource_array[idx] = 0u;
614                 info->resource_cnt--;
615                 break;
616             }
617         }
618     }
619
620     if (info->deleted && info->resource_cnt == 0) {
621         DbgPrint("Destroy buffer handle\n");
622
623         dynamicbox_destroy_buffer(info->handle);
624         free(info->resource_array);
625         free(info->id);
626         free(info);
627     }
628 }
629
630 static void *alloc_fb(void *data, int size)
631 {
632     vwin_info_t info = data;
633     void *buffer;
634
635     if (info->ee) {
636         ecore_evas_geometry_get(info->ee, NULL, NULL, &info->w, &info->h);
637         DbgPrint("Size of ee is updated: %dx%d (info: %p)\n", info->w, info->h, info);
638     }
639
640     if (!info->handle) {
641         ErrPrint("Failed to create a buffer\n");
642         return NULL;
643     }
644
645     if (dynamicbox_acquire_buffer(info->handle, DBOX_PRIMARY_BUFFER, info->w, info->h, sizeof(int)) < 0) {
646         ErrPrint("Failed to acquire buffer\n");
647         return NULL;
648     }
649
650     /**
651      * If it supports the H/W accelerated buffer,
652      * Use it.
653      */
654     if (dynamicbox_support_hw_buffer(info->handle)) {
655         if (dynamicbox_create_hw_buffer(info->handle) == 0) {
656             buffer = dynamicbox_buffer_hw_buffer(info->handle);
657             if (buffer) {
658                 DbgPrint("HW Accelerated buffer is created %p, (%dx%d)\n", info, info->w, info->h);
659                 info->type = VWIN_GEM;
660                 return buffer;
661             }
662         }
663
664         ErrPrint("Failed to allocate HW Accelerated buffer\n");
665     }
666
667     /**
668      * Or use the buffer of a S/W backend.
669      */
670     buffer = dynamicbox_ref_buffer(info->handle);
671     DbgPrint("SW buffer is created (%dx%d)\n", info->w, info->h);
672     info->type = VWIN_SW_BUF;
673     return buffer;
674 }
675
676 static void *alloc_stride_fb(void *data, int size, int *stride, int *bpp)
677 {
678     void *buffer;
679
680     buffer = alloc_fb(data, size);
681     if (buffer) {
682         vwin_info_t info = data;
683         int _stride;
684
685         *bpp = sizeof(int);
686         _stride = dynamicbox_buffer_stride(info->handle);
687         if (_stride < 0) {
688             _stride = info->w * *bpp;
689         }
690
691         *stride = _stride;
692         *bpp <<= 3;
693         DbgPrint("bpp: %d, stride: %d\n", *bpp, *stride);
694     }
695
696     return buffer;
697 }
698
699 static void free_fb(void *data, void *ptr)
700 {
701     vwin_info_t info = data;
702
703     if (!info->handle) {
704         return;
705     }
706
707     if (info->type == VWIN_GEM) {
708         if (dynamicbox_destroy_hw_buffer(info->handle) == 0) {
709             DbgPrint("HW Accelerated buffer is destroyed\n");
710         }
711     } else if (info->type == VWIN_SW_BUF) {
712         DbgPrint("SW buffer is destroyed, %p\n", info);
713         dynamicbox_unref_buffer(ptr);
714     } else if (info->type == VWIN_PIXMAP) {
715         ErrPrint("Unable to reach to here\n");
716     }
717
718     if (dynamicbox_release_buffer(info->handle, DBOX_PRIMARY_BUFFER) < 0) {
719         ErrPrint("Failed to release buffer\n");
720     }
721
722     if (info->deleted) {
723         dynamicbox_destroy_buffer(info->handle);
724         free(info->resource_array);
725         free(info->id);
726         free(info);
727     }
728 }
729
730 static void pre_render_cb(void *data, Evas *e, void *event_info)
731 {
732     vwin_info_t info = data;
733
734     if (!info->handle) {
735         return;
736     }
737
738     if (dynamicbox_conf_premultiplied_alpha()) {
739         Evas_Coord w;
740         Evas_Coord h;
741
742         ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
743         evas_damage_rectangle_add(e, 0, 0, w, h);
744     }
745
746     if (info->type == VWIN_GEM) {
747         dynamicbox_buffer_pre_render(info->handle);
748     } else if (info->type == VWIN_PIXMAP) {
749         /**
750          * Only the pixmap type Ecore_Evas uses this variable
751          */
752         info->front_resource_id = ecore_evas_gl_x11_pixmap_get(info->ee);
753     } else if (info->type == VWIN_SW_BUF) {
754         /* Do nothing */
755     }
756 }
757
758 static void post_render_cb(void *data, Evas *e, void *event_info)
759 {
760     vwin_info_t info = data;
761
762     if (!info->handle) {
763         return;
764     }
765
766     if (dynamicbox_conf_premultiplied_alpha()) {
767         void *canvas;
768         int x, y, w, h;
769
770         // Get a pointer of a buffer of the virtual canvas
771         canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
772         if (!canvas) {
773             ErrPrint("Failed to get pixel canvas\n");
774             return;
775         }
776
777         ecore_evas_geometry_get(info->ee, &x, &y, &w, &h);
778         evas_data_argb_unpremul(canvas, w * h);
779     }
780
781     if (info->type == VWIN_GEM) {
782         dynamicbox_buffer_post_render(info->handle);
783     } else if (info->type == VWIN_PIXMAP) {
784         int idx;
785
786         for (idx = 0; idx < DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT; idx++) {
787             if (info->front_resource_id == info->resource_array[idx]) {
788                 /**
789                  */
790                 dynamicbox_send_updated_by_idx(info->handle, idx);
791                 break;
792             }
793         }
794
795         if (idx == DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT) {
796             /* Send updated event for PRIMARY BUFFER */
797             if (info->front_resource_id == dynamicbox_resource_id(info->handle, DBOX_PRIMARY_BUFFER)) {
798                 dynamicbox_send_updated_by_idx(info->handle, DBOX_PRIMARY_BUFFER);
799             } else {
800                 DbgPrint("Unable to send updated: %u (%u)\n", info->front_resource_id, dynamicbox_resource_id(info->handle, DBOX_PRIMARY_BUFFER));
801             }
802         }
803     } else if (info->type == VWIN_SW_BUF) {
804         dynamicbox_sync_buffer(info->handle);
805     }
806 }
807
808 static void ecore_evas_free_cb(Ecore_Evas *ee)
809 {
810     vwin_info_t info;
811
812     info = ecore_evas_data_get(ee, "dynamic,box,info");
813     if (!info) {
814         DbgPrint("Info is not valid\n");
815         return;
816     }
817
818     if (info->e) {
819         evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_POST, post_render_cb);
820         evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb);
821     }
822
823     info->deleted = 1;
824     info->ee = NULL;
825 }
826
827 PUBLIC void *dynamicbox_get_evas_object(const char *id, int is_gbar)
828 {
829     vwin_info_t info;
830     Evas_Object *rect;
831     const char *engine;
832     int gl_is_turned_on = 0;
833
834     if (!s_info.alloc_canvas && !s_info.alloc_canvas_with_stride && !s_info.alloc_canvas_with_pixmap) {
835         s_info.alloc_canvas_with_pixmap = dlsym(RTLD_DEFAULT, "ecore_evas_gl_x11_pixmap_allocfunc_new");
836         if (!s_info.alloc_canvas_with_pixmap) {
837             DbgPrint("pixmap_allocfunc_new is not found\n");
838         }
839
840         s_info.alloc_canvas_with_stride = dlsym(RTLD_DEFAULT, "ecore_evas_buffer_allocfunc_with_stride_new");
841         if (!s_info.alloc_canvas_with_stride) {
842             DbgPrint("allocfunc_with_stirde_new is not found\n");
843         }
844
845         s_info.alloc_canvas = dlsym(RTLD_DEFAULT, "ecore_evas_buffer_allocfunc_new");
846         if (!s_info.alloc_canvas) {
847             ErrPrint("allocfunc_new is not found\n");
848         }
849
850         if (!s_info.alloc_canvas_with_stride && !s_info.alloc_canvas && !s_info.alloc_canvas_with_pixmap) {
851             ErrPrint("No way to allocate canvas\n");
852             return NULL;
853         }
854     }
855
856     if (!id) {
857         ErrPrint("Invalid parameter\n");
858         return NULL;
859     }
860
861     info = calloc(1, sizeof(*info));
862     if (!info) {
863         ErrPrint("Heap: %s\n", strerror(errno));
864         return NULL;
865     }
866
867     info->id = strdup(id);
868     if (!info->id) {
869         ErrPrint("Heap: %s\n", strerror(errno));
870         free(info);
871         return NULL;
872     }
873
874     info->is_gbar = is_gbar;
875
876     /**
877      * Acquire a buffer for canvas.
878      */
879     info->handle = dynamicbox_create_buffer(info->id, info->is_gbar,
880             (dynamicbox_conf_auto_align() || !s_info.alloc_canvas_with_stride),
881             event_handler_cb, info);
882
883     if (!info->handle) {
884         ErrPrint("Failed to create a dynamicbox buffer\n");
885         free(info->id);
886         free(info);
887         return NULL;
888     }
889
890     /**
891      * Size information must be initialized before call the ecore_evas_buffer_new.
892      */
893     info->w = DBOX_DEFAULT_WIDTH;
894     info->h = DBOX_DEFAULT_HEIGHT;
895
896     engine = elm_config_preferred_engine_get();
897     DbgPrint("Preferred engine: %s (%s)\n", engine, GL_ENGINE);
898     if (engine && !strcmp(engine, GL_ENGINE)) {
899         if (s_info.alloc_canvas_with_pixmap) {
900             info->ee = s_info.alloc_canvas_with_pixmap(NULL, 0u, 0, 0, info->w, info->h, alloc_pixmap_cb, free_pixmap_cb, info);
901             if (!info->ee) {
902                 ErrPrint("Unable to create a ee for pixmap\n");
903             } else {
904                 gl_is_turned_on = 1;
905             }
906         }
907     }
908
909     if (!info->ee) {
910         if (!dynamicbox_conf_auto_align() && s_info.alloc_canvas_with_stride) {
911             info->ee = s_info.alloc_canvas_with_stride(info->w, info->h, alloc_stride_fb, free_fb, info);
912         } else if (s_info.alloc_canvas) {
913             info->ee = s_info.alloc_canvas(info->w, info->h, alloc_fb, free_fb, info);
914         }
915     }
916
917     if (!info->ee) {
918         ErrPrint("Failed to create ecore_evas (%dx%d)\n", info->w, info->h);
919         dynamicbox_destroy_buffer(info->handle);
920         free(info->id);
921         free(info);
922         return NULL;
923     }
924
925     ecore_evas_data_set(info->ee, "dynamic,box,info", info);
926
927     /**
928      * @note
929      * Free callback must be prepared before use the ecore_evas_free()
930      */
931     ecore_evas_callback_pre_free_set(info->ee, ecore_evas_free_cb);
932
933     info->e = ecore_evas_get(info->ee);
934     if (!info->e) {
935         ErrPrint("Failed to get evas\n");
936         ecore_evas_free(info->ee);
937         return NULL;
938     }
939
940     if (!gl_is_turned_on) {
941         pre_render_cb(info, NULL, NULL);
942         ecore_evas_alpha_set(info->ee, EINA_TRUE);
943         post_render_cb(info, NULL, NULL);
944     } else {
945         DbgPrint("opengl-x11 engine should not turn on the alpha\n");
946     }
947
948     ecore_evas_manual_render_set(info->ee, EINA_FALSE);
949     ecore_evas_resize(info->ee, info->w, info->h);
950
951     evas_event_callback_add(info->e, EVAS_CALLBACK_RENDER_POST, post_render_cb, info);
952     evas_event_callback_add(info->e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, info);
953
954     rect = evas_object_rectangle_add(info->e);
955     if (!rect) {
956         ErrPrint("Failed to create evas_object\n");
957         ecore_evas_free(info->ee);
958         return NULL;
959     }
960
961     evas_object_resize(rect, info->w, info->h);
962     evas_object_color_set(rect, 0, 0, 0, 0);
963     return rect;
964 }
965
966 /* End of a file */