a839c872acaf9c5c297bbefe3bda61a8eb565c16
[apps/native/widget/widget.git] / src / binder.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define __USE_GNU
4 #include <dlfcn.h>
5 #define _GNU_SOURCE
6 #include <string.h>
7
8 #include <Elementary.h>
9 #include <Ecore_Evas.h>
10
11 #include <widget_errno.h>
12 #include <widget_service.h>
13 #include <widget_service_internal.h>
14 #include <widget_provider.h>
15 #include <widget_provider_buffer.h>
16 #include <widget_conf.h>
17
18 #include <dlog.h>
19
20 #include "widget.h"
21 #include "widget_internal.h"
22 #include "binder.h"
23 #include "debug.h"
24 #include "util.h"
25
26 #define PUBLIC __attribute__((visibility("default")))
27
28 /**
29  * @brief These functions are defined in the data-provider-slave
30  */
31 static struct info {
32         const char *(*find_pkgname)(const char *filename);
33         int (*request_update_by_id)(const char *uri);
34         int (*trigger_update_monitor)(const char *id, int is_gbar);
35         int (*update_extra_info)(const char *id, const char *content, const char *title, const char *icon, const char *name);
36         int (*add_pre_callback)(widget_pre_callback_e type, widget_pre_callback_t cb, void *data);
37         int (*del_pre_callback)(widget_pre_callback_e type, widget_pre_callback_t cb, void *data);
38         int (*orientation)(const char *id);
39         Ecore_Evas *(*alloc_canvas)(int w, int h, void *(*a)(void *data, int size), void (*f)(void *data, void *ptr), void *data);
40         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);
41         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);
42
43         enum load_type {
44                 LOAD_TYPE_UNKNOWN = -1,
45                 LOAD_TYPE_SLAVE   = 0,
46                 LOAD_TYPE_APP     = 1
47         } type;
48
49         union _updated {
50                 struct _slave {
51                         int (*send)(const char *pkgname, const char *id, widget_buffer_h handle, int idx, int x, int y, int w, int h, int gbar, const char *descfile);
52                 } slave;
53
54                 struct _app {
55                         int (*send)(widget_buffer_h handle, int idx, int x, int y, int w, int h, int gbar);
56                 } app;
57         } binder;
58 } s_info = {
59         .find_pkgname = NULL,
60         .request_update_by_id = NULL,
61         .trigger_update_monitor = NULL,
62         .update_extra_info = NULL,
63         .add_pre_callback = NULL,
64         .del_pre_callback = NULL,
65         .orientation = NULL,
66         .alloc_canvas = NULL,
67         .alloc_canvas_with_stride = NULL,
68         .alloc_canvas_with_pixmap = NULL,
69         .type = LOAD_TYPE_UNKNOWN,    /* Not initialized */
70         .binder = {
71                 .slave = {
72                         .send = NULL,
73                 },
74                 .app = {
75                         .send = NULL,
76                 },
77         },
78 };
79
80 #define FUNC_PREFIX                               "widget_"
81 #define FUNC_WIDGET_SEND_UPDATED                  FUNC_PREFIX "send_buffer_updated"
82 #define FUNC_WIDGET_FIND_PKGNAME                  FUNC_PREFIX "find_pkgname"
83 #define FUNC_WIDGET_REQUEST_UPDATE_BY_ID          FUNC_PREFIX "request_update_by_id"
84 #define FUNC_WIDGET_TRIGGER_UPDATE_MONITOR        FUNC_PREFIX "trigger_update_monitor"
85 #define FUNC_WIDGET_UPDATE_EXTRA_INFO             FUNC_PREFIX "update_extra_info"
86
87 #define FUNC_WIDGET_PROVIDER_APP_UPDATED          FUNC_PREFIX "provider_app_send_buffer_updated_event"
88
89 #define FUNC_WIDGET_PROVIDER_APP_ADD_PRE_CALLBACK FUNC_PREFIX "provider_app_add_pre_callback"
90 #define FUNC_WIDGET_PROVIDER_APP_DEL_PRE_CALLBACK FUNC_PREFIX "provider_app_del_pre_callback"
91 #define FUNC_WIDGET_PROVIDER_APP_ORIENTATION      FUNC_PREFIX "provider_app_get_orientation"
92
93 static inline void load_ecore_evas_function(void)
94 {
95         if (!s_info.alloc_canvas && !s_info.alloc_canvas_with_stride && !s_info.alloc_canvas_with_pixmap) {
96                 s_info.alloc_canvas_with_pixmap = dlsym(RTLD_DEFAULT, "ecore_evas_gl_x11_pixmap_allocfunc_new");
97                 if (!s_info.alloc_canvas_with_pixmap) {
98                         DbgPrint("pixmap_allocfunc_new is not found\n");
99                 }
100
101                 s_info.alloc_canvas_with_stride = dlsym(RTLD_DEFAULT, "ecore_evas_buffer_allocfunc_with_stride_new");
102                 if (!s_info.alloc_canvas_with_stride) {
103                         DbgPrint("allocfunc_with_stirde_new is not found\n");
104                 }
105
106                 s_info.alloc_canvas = dlsym(RTLD_DEFAULT, "ecore_evas_buffer_allocfunc_new");
107                 if (!s_info.alloc_canvas) {
108                         ErrPrint("allocfunc_new is not found\n");
109                 }
110
111                 if (!s_info.alloc_canvas_with_stride && !s_info.alloc_canvas && !s_info.alloc_canvas_with_pixmap) {
112                         ErrPrint("No way to allocate canvas\n");
113                 }
114         }
115 }
116
117 static inline void load_update_function(void)
118 {
119         /* Must to be checked the slave function first. */
120         s_info.binder.slave.send = dlsym(RTLD_DEFAULT, FUNC_WIDGET_SEND_UPDATED);
121         if (s_info.binder.slave.send) {
122                 s_info.type = LOAD_TYPE_SLAVE;
123                 DbgPrint("Slave detected\n");
124         } else {
125                 s_info.binder.app.send = dlsym(RTLD_DEFAULT, FUNC_WIDGET_PROVIDER_APP_UPDATED);
126                 if (s_info.binder.app.send) {
127                         s_info.type = LOAD_TYPE_APP;
128                         DbgPrint("App detected\n");
129                 }
130         }
131 }
132
133 PUBLIC int widget_get_orientation(const char *id)
134 {
135         if (!s_info.orientation) {
136                 s_info.orientation = dlsym(RTLD_DEFAULT, FUNC_WIDGET_PROVIDER_APP_ORIENTATION);
137                 if (!s_info.orientation) {
138                         return WIDGET_ERROR_NOT_SUPPORTED;
139                 }
140         }
141
142         return s_info.orientation(id);
143 }
144
145 PUBLIC int widget_add_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
146 {
147         if (!s_info.add_pre_callback) {
148                 s_info.add_pre_callback = dlsym(RTLD_DEFAULT, FUNC_WIDGET_PROVIDER_APP_ADD_PRE_CALLBACK);
149                 if (!s_info.add_pre_callback) {
150                         return WIDGET_ERROR_NOT_SUPPORTED;
151                 }
152         }
153
154         return s_info.add_pre_callback(type, cb, data);
155 }
156
157 PUBLIC int widget_del_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
158 {
159         if (!s_info.del_pre_callback) {
160                 s_info.del_pre_callback = dlsym(RTLD_DEFAULT, FUNC_WIDGET_PROVIDER_APP_DEL_PRE_CALLBACK);
161                 if (!s_info.del_pre_callback) {
162                         return WIDGET_ERROR_NOT_SUPPORTED;
163                 }
164         }
165
166         return s_info.del_pre_callback(type, cb, data);
167 }
168
169 int binder_widget_send_updated(const char *pkgname, const char *id, widget_buffer_h handle, int idx, int x, int y, int w, int h, int gbar, const char *descfile)
170 {
171         int ret = WIDGET_ERROR_INVALID_PARAMETER;
172
173         if (s_info.type == LOAD_TYPE_UNKNOWN) {
174                 load_update_function();
175         }
176
177         if (s_info.type == LOAD_TYPE_APP) {
178                 ret = s_info.binder.app.send(handle, idx, x, y, w, h, gbar);
179         } else if (s_info.type == LOAD_TYPE_SLAVE) {
180                 /**
181                  * pkgname, id are used for finding handle of direct connection.
182                  */
183                 ret = s_info.binder.slave.send(pkgname, id, handle, idx, x, y, w, h, gbar, descfile);
184         } else {
185                 widget_damage_region_s region = {
186                         .x = x,
187                         .y = y,
188                         .w = w,
189                         .h = h,
190                 };
191                 ret = widget_provider_send_buffer_updated(handle, idx, &region, gbar, descfile);
192         }
193
194         return ret;
195 }
196
197 PUBLIC int widget_content_is_updated(const char *filename, int is_gbar)
198 {
199         if (!s_info.trigger_update_monitor) {
200                 s_info.trigger_update_monitor = dlsym(RTLD_DEFAULT, FUNC_WIDGET_TRIGGER_UPDATE_MONITOR);
201                 if (!s_info.trigger_update_monitor) {
202                         ErrPrint("Trigger update monitor function is not exists\n");
203                         return WIDGET_ERROR_FAULT;
204                 }
205         }
206
207         return s_info.trigger_update_monitor(filename, is_gbar);
208 }
209
210 const char *binder_widget_find_pkgname(const char *uri)
211 {
212         const char *pkgname;
213
214         if (!s_info.find_pkgname) {
215                 s_info.find_pkgname = dlsym(RTLD_DEFAULT, FUNC_WIDGET_FIND_PKGNAME);
216                 if (!s_info.find_pkgname) {
217                         ErrPrint("Failed to find a \"widget_find_pkgname\"\n");
218                         return NULL;
219                 }
220         }
221
222         pkgname = s_info.find_pkgname(uri);
223         if (!pkgname) {
224                 ErrPrint("Failed to find a package (%s)\n", uri);
225                 return NULL;
226         }
227
228         return pkgname;
229 }
230
231 PUBLIC int widget_request_update(const char *filename)
232 {
233         char *uri;
234         int ret;
235
236         if (!filename) {
237                 ErrPrint("Invalid argument\n");
238                 return WIDGET_ERROR_INVALID_PARAMETER;
239         }
240
241         uri = util_id_to_uri(filename);
242         if (!uri) {
243                 ErrPrint("Heap: %d\n", errno);
244                 return WIDGET_ERROR_OUT_OF_MEMORY;
245         }
246
247         if (!s_info.request_update_by_id) {
248                 s_info.request_update_by_id = dlsym(RTLD_DEFAULT, FUNC_WIDGET_REQUEST_UPDATE_BY_ID);
249                 if (!s_info.request_update_by_id) {
250                         ErrPrint("\"widget_request_update_by_id\" is not exists\n");
251                         free(uri);
252                         return WIDGET_ERROR_FAULT;
253                 }
254         }
255
256         ret = s_info.request_update_by_id(uri);
257         free(uri);
258         return ret;
259 }
260
261 int binder_widget_update_extra_info(const char *id, const char *content, const char *title, const char *icon, const char *name)
262 {
263         if (!s_info.update_extra_info) {
264                 s_info.update_extra_info = dlsym(RTLD_DEFAULT, FUNC_WIDGET_UPDATE_EXTRA_INFO);
265                 if (!s_info.update_extra_info) {
266                         ErrPrint("Failed to find a \"widget_update_extra_info\"\n");
267                         return WIDGET_ERROR_INVALID_PARAMETER;
268                 }
269         }
270
271         return s_info.update_extra_info(id, content, title, icon, name);
272 }
273
274 /**
275  * @note
276  * This callback can be called twice (or more) to get a several pixmaps
277  * Acquired pixmaps are used for double/tripple buffering for canvas
278  */
279 static Ecore_X_Pixmap alloc_pixmap_cb(void *data, Ecore_X_Window parent, int w, int h, int depth)
280 {
281         vwin_info_t info = data;
282         Ecore_X_Pixmap pixmap;
283
284         if (!info->handle) {
285                 ErrPrint("Invalid handle\n");
286                 return 0u;
287         }
288
289         info->w = w;
290         info->h = h;
291         DbgPrint("Size of ee is updated: %dx%d - %d (info: %p)\n", info->w, info->h, depth, info);
292         depth >>= 3;
293
294         if (widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER) == 0u) {
295                 /**
296                  * @note
297                  * Need to allocate a primary buffer
298                  */
299                 widget_viewer_acquire_buffer(info->handle, WIDGET_PRIMARY_BUFFER, info->w, info->h, depth);
300                 if (!info->handle) {
301                         ErrPrint("Failed to get the buffer\n");
302                         return 0u;
303                 }
304
305                 pixmap = (Ecore_X_Pixmap)widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER);
306         } else if (WIDGET_CONF_EXTRA_BUFFER_COUNT > 0) {
307                 int idx;
308
309                 if (!info->resource_array) {
310                         info->resource_array = calloc(WIDGET_CONF_EXTRA_BUFFER_COUNT, sizeof(*info->resource_array));
311                         if (!info->resource_array) {
312                                 ErrPrint("Out of memory: %d\n", errno);
313                                 return 0u;
314                         }
315
316                         idx = 0;
317                 } else {
318                         for (idx = 0; idx < WIDGET_CONF_EXTRA_BUFFER_COUNT; idx++) {
319                                 if (info->resource_array[idx] == 0u) {
320                                         break;
321                                 }
322                         }
323
324                         if (idx == WIDGET_CONF_EXTRA_BUFFER_COUNT) {
325                                 ErrPrint("Out of index: %d\n", idx);
326                                 return 0u;
327                         }
328                 }
329
330                 if (widget_viewer_acquire_buffer(info->handle, idx, info->w, info->h, depth) < 0) {
331                         ErrPrint("Failed to acquire a buffer for %d\n", idx);
332                         return 0u;
333                 }
334
335                 info->resource_array[idx] = widget_viewer_get_resource_id(info->handle, idx);
336                 if (info->resource_array[idx] == 0u) {
337                         ErrPrint("Failed to allocate pixmap\n");
338                 }
339
340                 DbgPrint("Allocated index: %d/%d - %u\n", idx, WIDGET_CONF_EXTRA_BUFFER_COUNT, info->resource_array[idx]);
341                 pixmap = info->resource_array[idx];
342         } else {
343                 ErrPrint("Unable to allocate pixmap\n");
344                 pixmap = 0u;
345         }
346
347         /**
348          * Acquire a buffer for canvas.
349          */
350         info->type = VWIN_PIXMAP;
351         info->resource_cnt += !!(unsigned int)pixmap;
352         return pixmap;
353 }
354
355 static void free_pixmap_cb(void *data, Ecore_X_Pixmap pixmap)
356 {
357         vwin_info_t info = data;
358
359         if (!info->handle) {
360                 return;
361         }
362
363         if (info->type != VWIN_PIXMAP) {
364                 ErrPrint("Impossible\n");
365         }
366
367         if (widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER) == pixmap) {
368                 if (widget_viewer_release_buffer(info->handle, WIDGET_PRIMARY_BUFFER) < 0) {
369                         DbgPrint("Failed to release buffer\n");
370                 }
371                 info->resource_cnt--;
372         } else {
373                 int idx;
374
375                 for (idx = 0; idx < WIDGET_CONF_EXTRA_BUFFER_COUNT; idx++) {
376                         /**
377                          * @note
378                          * Find a index to release it
379                          */
380                         if (info->resource_array[idx] == pixmap) {
381                                 if (widget_viewer_release_buffer(info->handle, idx) < 0) {
382                                         DbgPrint("Failed to release buffer\n");
383                                 }
384                                 info->resource_array[idx] = 0u;
385                                 info->resource_cnt--;
386                                 break;
387                         }
388                 }
389         }
390
391         if (info->deleted && info->resource_cnt == 0) {
392                 DbgPrint("Destroy buffer handle\n");
393
394                 info->state = VWIN_INFO_DESTROYED;
395                 widget_destroy_buffer(info->handle);
396                 free(info->resource_array);
397                 free(info->id);
398                 free(info);
399         }
400 }
401
402 static void *alloc_fb(void *data, int size)
403 {
404         vwin_info_t info = data;
405         void *buffer;
406
407         if (info->ee) {
408                 ecore_evas_geometry_get(info->ee, NULL, NULL, &info->w, &info->h);
409                 DbgPrint("Size of ee is updated: %dx%d (info: %p)\n", info->w, info->h, info);
410         }
411
412         if (!info->handle) {
413                 ErrPrint("Failed to create a buffer\n");
414                 return NULL;
415         }
416
417         if (widget_viewer_acquire_buffer(info->handle, WIDGET_PRIMARY_BUFFER, info->w, info->h, sizeof(int)) < 0) {
418                 ErrPrint("Failed to acquire buffer\n");
419                 return NULL;
420         }
421
422         /**
423          * If it supports the H/W accelerated buffer,
424          * Use it.
425          */
426         if (widget_support_hw_buffer(info->handle)) {
427                 if (widget_create_hw_buffer(info->handle) == 0) {
428                         buffer = widget_buffer_hw_buffer(info->handle);
429                         if (buffer) {
430                                 DbgPrint("HW Accelerated buffer is created %p, (%dx%d)\n", info, info->w, info->h);
431                                 info->type = VWIN_GEM;
432                                 return buffer;
433                         }
434                 }
435
436                 ErrPrint("Failed to allocate HW Accelerated buffer\n");
437         }
438
439         /**
440          * Or use the buffer of a S/W backend.
441          */
442         buffer = widget_ref_buffer(info->handle);
443         DbgPrint("SW buffer is created (%dx%d)\n", info->w, info->h);
444         info->type = VWIN_SW_BUF;
445         return buffer;
446 }
447
448 static void *alloc_stride_fb(void *data, int size, int *stride, int *bpp)
449 {
450         void *buffer;
451
452         buffer = alloc_fb(data, size);
453         if (buffer) {
454                 vwin_info_t info = data;
455                 int _stride;
456
457                 *bpp = sizeof(int);
458                 _stride = widget_buffer_stride(info->handle);
459                 if (_stride < 0) {
460                         _stride = info->w * *bpp;
461                 }
462
463                 *stride = _stride;
464                 *bpp <<= 3;
465                 DbgPrint("bpp: %d, stride: %d\n", *bpp, *stride);
466         }
467
468         return buffer;
469 }
470
471 static void free_fb(void *data, void *ptr)
472 {
473         vwin_info_t info = data;
474
475         if (!info->handle) {
476                 return;
477         }
478
479         if (info->type == VWIN_GEM) {
480                 if (widget_destroy_hw_buffer(info->handle) == 0) {
481                         DbgPrint("HW Accelerated buffer is destroyed\n");
482                 }
483         } else if (info->type == VWIN_SW_BUF) {
484                 DbgPrint("SW buffer is destroyed, %p\n", info);
485                 widget_unref_buffer(ptr);
486         } else if (info->type == VWIN_PIXMAP) {
487                 ErrPrint("Unable to reach to here\n");
488         }
489
490         if (widget_viewer_release_buffer(info->handle, WIDGET_PRIMARY_BUFFER) < 0) {
491                 ErrPrint("Failed to release buffer\n");
492         }
493
494         if (info->deleted) {
495                 info->state = VWIN_INFO_DESTROYED;
496                 widget_destroy_buffer(info->handle);
497                 free(info->resource_array);
498                 free(info->id);
499                 free(info);
500         }
501 }
502
503 static inline int check_gl_engine(const char *engine)
504 {
505         /**
506          * @todo
507          * If the "engine" string going to be changed to more complicated formatted string,
508          * We should replace this with sytanx recognizer (parser).
509          */
510         return !!strcasestr(engine, GL_ENGINE);
511 }
512
513 Ecore_Evas *binder_ecore_evas_new(vwin_info_t info)
514 {
515         const char *engine;
516         Ecore_Evas *ee = NULL;
517
518         load_ecore_evas_function();
519
520         engine = elm_config_accel_preference_get();
521
522         DbgPrint("Preferred engine: %s (%s or %s)\n", engine, GL_ENGINE, GL_ENGINE_X11);
523         if (engine && check_gl_engine(engine)) {
524                 if (s_info.alloc_canvas_with_pixmap) {
525                         ee = s_info.alloc_canvas_with_pixmap(NULL, 0u, 0, 0, info->w, info->h, alloc_pixmap_cb, free_pixmap_cb, info);
526                         if (!ee) {
527                                 ErrPrint("Unable to create a ee for pixmap\n");
528                         }
529                 }
530         }
531
532         if (!ee) {
533                 if (!widget_conf_auto_align() && s_info.alloc_canvas_with_stride) {
534                         ee = s_info.alloc_canvas_with_stride(info->w, info->h, alloc_stride_fb, free_fb, info);
535                 } else if (s_info.alloc_canvas) {
536                         ee = s_info.alloc_canvas(info->w, info->h, alloc_fb, free_fb, info);
537                 }
538         }
539
540         return ee;
541 }
542
543 int binder_widget_auto_align(void)
544 {
545         load_ecore_evas_function();
546
547         return widget_conf_auto_align() || !s_info.alloc_canvas_with_stride;
548 }
549
550 /* End of a file */