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