328126d7baf322c3c34fe094ed8bb2de4fe767c2
[apps/native/widget/widget.git] / src / virtual_window.c
1 #include <Ecore_Evas.h>
2 #include <Evas.h>
3
4 #include <dlog.h>
5 #include <livebox-errno.h>
6
7 #include "livebox.h"
8
9 #define IS_PD 1
10
11 #define PUBLIC __attribute__((visibility("default")))
12 /*!
13  * \brief
14  * Abstracted Data Type of Virtual Window
15  */
16 struct info {
17         char *id; /*!< Identification */
18         int width; /*!< Width */
19         int height; /*!< Height */
20         struct livebox_buffer *handle; /*!< Livebox buffer handle */
21         Evas_Object *window; /*!< Parent evas object - WARN: Incompatible with the elm_win object */
22         int is_hw; /*!< 1 if a buffer is created on the H/W accelerated place or 0 */
23 };
24
25 /*!
26  * \note
27  * Every user event (mouse) on the buffer will be passed via this event callback
28  */
29 static int event_handler_cb(struct livebox_buffer *handler, enum buffer_event evt, double timestamp, double x, double y, void *data)
30 {
31         struct info *info = data;
32         Evas *e;
33         int ix;
34         int iy;
35
36         if (!info->handle) {
37                 /* Just ignore this event */
38                 return 0;
39         }
40
41         /*!
42          * \note
43          * Calculate the event occurred X & Y on the buffer
44          */
45         ix = info->width * x;
46         iy = info->height * y;
47
48         e = evas_object_evas_get(info->window);
49
50         /*!
51          * \note
52          * Feed up events
53          */
54         switch (evt) {
55         case BUFFER_EVENT_ENTER:
56                 evas_event_feed_mouse_in(e, timestamp, NULL);
57                 break;
58         case BUFFER_EVENT_LEAVE:
59                 evas_event_feed_mouse_out(e, timestamp, NULL);
60                 break;
61         case BUFFER_EVENT_DOWN:
62                 evas_event_feed_mouse_in(e, timestamp, NULL);
63                 evas_event_feed_mouse_move(e, ix, iy, timestamp + 0.01f, NULL); /* + 0.1f just for fake event */
64                 evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.02f, NULL); /* + 0.2f just for fake event */
65                 break;
66         case BUFFER_EVENT_MOVE:
67                 evas_event_feed_mouse_move(e, ix, iy, timestamp, NULL);
68                 break;
69         case BUFFER_EVENT_UP:
70                 evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
71                 evas_event_feed_mouse_out(e, timestamp + 0.01f, NULL); /* + 0.1f just for fake event */
72                 break;
73         default:
74                 LOGD("Unhandled buffer event (%d)\n", evt);
75                 break;
76         }
77
78         return 0;
79 }
80
81 static void *alloc_fb(void *data, int size)
82 {
83         struct info *info = data;
84         void *buffer;
85
86         /*!
87          * Acquire a buffer for canvas.
88          */
89         info->handle = livebox_acquire_buffer(info->id, IS_PD,
90                                         info->width, info->height,
91                                         event_handler_cb, info);
92
93         /*!
94          * If it supports the H/W accelerated buffer,
95          * Use it.
96          */
97         if (livebox_support_hw_buffer(info->handle)) {
98                 if (livebox_create_hw_buffer(info->handle) == 0) {
99                         buffer = livebox_buffer_hw_buffer(info->handle);
100                         if (buffer) {
101                                 LOGD("HW Accelerated buffer is created\n");
102                                 info->is_hw = 1;
103                                 return buffer;
104                         }
105                 }
106
107                 LOGE("Failed to allocate HW Accelerated buffer\n");
108         }
109
110         /*!
111          * Or use the buffer of a S/W backend.
112          */
113         buffer = livebox_ref_buffer(info->handle);
114         LOGD("SW buffer is created\n");
115         info->is_hw = 0;
116         return buffer;
117 }
118
119 static void free_fb(void *data, void *ptr)
120 {
121         struct info *info = data;
122
123         if (!info->handle)
124                 return;
125
126         if (info->is_hw) {
127                 if (livebox_destroy_hw_buffer(info->handle) == 0) {
128                         LOGD("HW Accelerated buffer is destroyed\n");
129                         goto out;
130                 }
131         }
132
133         livebox_unref_buffer(ptr);
134         LOGD("SW buffer is destroyed\n");
135 out:
136         livebox_release_buffer(info->handle);
137         info->handle = NULL;
138 }
139
140 static void resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
141 {
142         struct info *info = data;
143         Ecore_Evas *ee;
144
145         ee = ecore_evas_ecore_evas_get(e);
146         if (!ee)
147                 return;
148
149         evas_object_geometry_get(obj, NULL, NULL, &info->width, &info->height);
150         LOGD("Resize to %dx%d\n", info->width, info->height);
151         /*!
152          * Box(parent object) is resized.
153          * Try to resize the canvas too.
154          */
155         ecore_evas_resize(ee, info->width, info->height);
156 }
157
158 /*!
159  * If a canvas is destroyed,
160  * Free all buffer of canvas.
161  */
162 static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
163 {
164         Ecore_Evas *ee;
165         struct info *info = data;
166
167         ee = ecore_evas_ecore_evas_get(e);
168         if (!ee)
169                 return;
170
171         LOGD("Try to release the ECORE_EVAS\n");
172         ecore_evas_free(ee);
173         free(info->id);
174         free(info);
175         LOGD("ECORE_EVAS is released\n");
176 }
177
178 static void pre_render_cb(void *data, Evas *e, void *event_info)
179 {
180         struct info *info = data;
181
182         if (!info->handle)
183                 return;
184
185         if (info->is_hw)
186                 livebox_buffer_pre_render(info->handle);
187 }
188
189 static void post_render_cb(void *data, Evas *e, void *event_info)
190 {
191         struct info *info = data;
192
193         if (!info->handle)
194                 return;
195
196         if (info->is_hw)
197                 livebox_buffer_post_render(info->handle);
198         else
199                 livebox_sync_buffer(info->handle);
200 }
201
202 PUBLIC Evas_Object *livebox_virtual_window_add(const char *id, int width, int height)
203 {
204         Ecore_Evas *ee;
205         Evas *e;
206         struct info *info;
207
208         info = calloc(1, sizeof(*info));
209         if (!info) {
210                 return NULL;
211         }
212
213         info->id = strdup(id);
214         if (!info->id) {
215                 free(info);
216                 return NULL;
217         }
218
219         info->width = width;
220         info->height = height;
221
222         ee = ecore_evas_buffer_allocfunc_new(width, height, alloc_fb, free_fb, info);
223         if (!ee) {
224                 free(info->id);
225                 free(info);
226                 return NULL;
227         }
228
229         pre_render_cb(info, NULL, NULL);
230         ecore_evas_alpha_set(ee, EINA_TRUE);
231         post_render_cb(info, NULL, NULL);
232         
233         ecore_evas_manual_render_set(ee, EINA_FALSE);
234         ecore_evas_resize(ee, width, height);
235
236         e = ecore_evas_get(ee);
237         if (!e) {
238                 ecore_evas_free(ee);
239                 return NULL;
240         }
241
242         evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, post_render_cb, info);
243         evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, info);
244
245         info->window = evas_object_rectangle_add(e);
246         if (!info->window) {
247                 ecore_evas_free(ee);
248                 return NULL;
249         }
250
251         evas_object_resize(info->window, width, height);
252         evas_object_color_set(info->window, 0, 0, 0, 0);
253         evas_object_event_callback_add(info->window, EVAS_CALLBACK_DEL, del_cb, info);
254         evas_object_event_callback_add(info->window, EVAS_CALLBACK_RESIZE, resize_cb, info);
255
256         return info->window;
257 }
258
259 PUBLIC int livebox_virtual_window_del(Evas_Object *virtual_win)
260 {
261         evas_object_del(virtual_win);
262         return LB_STATUS_SUCCESS;
263 }
264
265 /* End of a file */