9eab3e0b6ae15a7d470a5bf36ff12072f0f210df
[platform/core/uifw/libpui.git] / src / PUI.c
1 /*
2  * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "PUI_internal.h"
27 #include "PUI_backend.h"
28 #include "PUI.h"
29
30 #include <wayland-tbm-client.h>
31 #include <tbm_surface_internal.h>
32 #include <stdio.h>
33 #include <dlfcn.h>
34
35 #ifndef PUI_MODULE_DIR
36 #define PUI_MODULE_DIR "/usr/lib"
37 #endif
38
39 static int _pui_init_count = 0;
40 static pui_module_data *pui_module = NULL;
41
42 int PUI_EVENT_ANI_STARTED = 0;
43 int PUI_EVENT_ANI_STOPPED = 0;
44 int PUI_EVENT_ANI_PAUSED = 0;
45 int PUI_EVENT_ANI_READY_TO_START = 0;
46 int PUI_EVENT_ANI_READY_TO_RESUME = 0;
47
48 static int KEY_WL_BUFFER = 0xabcdbeaf;
49 static int KEY_CLIENT = 0xdcbabeaf;
50
51 pui_error_string
52 pui_error_to_string(pui_error e)
53 {
54         pui_error_string str = NULL;
55
56         switch (e)
57         {
58                 case PUI_ERROR_NONE:
59                         str = "PUI_No_Error";
60                         break;
61
62                 case PUI_ERROR_INVALID_ANI_HANDLE:
63                         str = "PUI_Invalid_Animation_Handle";
64                         break;
65
66                 case PUI_ERROR_INVALID_ANI_CMD:
67                         str = "PUI_Invalid_Animation_Command";
68                         break;
69
70                 case PUI_ERROR_INTERNAL:
71                         str = "PUI_Internal_Error";
72                         break;
73
74                 case PUI_ERROR_MANUAL_RENDER_ENABLED:
75                         str = "PUI_Manual_Render_Enabled";
76                         break;
77
78                 case PUI_ERROR_UNABLE_SET_MANUAL_RENDER:
79                         str = "PUI_Unable_To_Set_Manual_Render";
80                         break;
81
82                 default:
83                         str = "PUI_Unknown_Error";
84         }
85
86         return str;
87 }
88
89 static void
90 _buffer_release(void *data, struct wl_buffer *buffer)
91 {
92         tbm_surface_h surface = (tbm_surface_h)data;
93         pui_h handle;
94
95         tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_CLIENT, (void **)&handle);
96         tbm_surface_queue_release(handle->tbm_queue, surface);
97
98         pui_info("[UPDATE] release wl_buffer:%p, surface:%p\n", buffer, surface);
99 }
100
101 static const struct wl_buffer_listener buffer_listener = {
102     _buffer_release
103 };
104
105 pui_ani_control_buffer *
106 pui_display_get_buffer(pui_h handle)
107 {
108         tbm_surface_error_e ret;
109         tbm_surface_h surface;
110         pui_ani_control_buffer *buffer = NULL;
111
112         if (!handle)
113         {
114                 pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
115                 return NULL;
116         }
117
118         if (handle->current_surface)
119         {
120                 pui_debug("[GET BUFFER] Current_surface is not used !\n");
121         }
122
123         if (!tbm_surface_queue_can_dequeue(handle->tbm_queue, 0))
124         {
125                 pui_err("[GET BUFFER] Failed to dequeue a tbm_surface !\n");
126                 return NULL;
127         }
128
129         ret = tbm_surface_queue_dequeue(handle->tbm_queue, &surface);
130
131         if (ret != TBM_SURFACE_ERROR_NONE)
132         {
133                 pui_err("[GET BUFFER] Dequeue err:%d\n", ret);
134                 return NULL;
135         }
136
137         tbm_surface_map(surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &handle->current_sinfo);
138
139         handle->current_surface = surface;
140         buffer = (pui_ani_control_buffer *)&(handle->current_sinfo.planes[0]);
141
142         return buffer;
143 }
144
145 pui_error
146 pui_display_set_buffer(pui_h handle, pui_ani_control_buffer *buffer)
147 {
148         if (!handle)
149         {
150                 pui_err("Error : PUI_ERROR_INVALID_HANDLE\n");
151                 return PUI_ERROR_INVALID_HANDLE;
152         }
153
154         if (!handle->current_surface)
155         {
156                 pui_err("Current_surface is not valid !\n");
157                 return PUI_ERROR_INVALID_SURFACE;
158         }
159
160         if (!buffer || !buffer->ptr || !buffer->size)
161                 return PUI_ERROR_INVALID_BUFFER;
162
163         handle->is_buffer_set = 1;
164
165         return PUI_ERROR_NONE;
166 }
167
168 pui_error
169 pui_display_update(pui_h handle)
170 {
171         tbm_surface_h surface;
172         tbm_surface_error_e ret;
173         struct wl_buffer *wl_buffer = NULL;
174
175         if (!handle)
176         {
177                 pui_err("Error : PUI_ERROR_INVALID_HANDLE\n");
178                 return PUI_ERROR_INVALID_HANDLE;
179         }
180
181         if (!handle->current_surface)
182                 return PUI_ERROR_INVALID_SURFACE;
183
184         if (!handle->is_buffer_set)
185         {
186                 pui_err("[UPDATE] Buffer is not set !\n");
187                 return PUI_ERROR_INVALID_BUFFER;
188         }
189
190         surface = handle->current_surface;
191         handle->current_surface = NULL;
192
193         tbm_surface_unmap(surface);
194
195         ret = tbm_surface_queue_enqueue(handle->tbm_queue, surface);
196
197         if (ret != TBM_SURFACE_ERROR_NONE)
198         {
199                 pui_err("[UPDATE] enqueue err:%d\n", ret);
200                 return PUI_ERROR_INVALID_SURFACE;
201         }
202
203         ret = tbm_surface_queue_acquire(handle->tbm_queue, &surface);
204
205         if (ret != TBM_SURFACE_ERROR_NONE)
206         {
207                 pui_err("[UPDATE] acquire err:%d\n", ret);
208                 return PUI_ERROR_INVALID_SURFACE;
209         }
210
211         if (!tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_WL_BUFFER, (void **)&wl_buffer)) {
212                 wl_buffer = wayland_tbm_client_create_buffer(handle->wl_tbm_client, surface);
213
214                 if (!wl_buffer)
215                 {
216                         pui_err("[UPDATE] failed to create wl_buffer tbm_surface:%p\n", surface);
217                         return PUI_ERROR_INVALID_BUFFER;
218                 }
219
220                 wl_buffer_add_listener(wl_buffer, &buffer_listener, surface);
221
222                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_WL_BUFFER, NULL);
223                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_WL_BUFFER, wl_buffer);
224                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_CLIENT, NULL);
225                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_CLIENT, handle);
226         }
227
228         if (!wl_buffer)
229         {
230                 pui_err("[UPDATE] dequeue err:%d\n", ret);
231                 return PUI_ERROR_INVALID_BUFFER;
232         }
233
234         ecore_wl2_window_buffer_attach(handle->win, wl_buffer, 0, 0, 0);
235         ecore_wl2_window_damage(handle->win, NULL, 0);
236         ecore_wl2_window_commit(handle->win, EINA_TRUE);
237
238         pui_info("[UPDATE] commit wl_buffer:%p, surface:%p\n", wl_buffer, surface);
239
240         handle->is_buffer_set = 0;
241
242         return PUI_ERROR_NONE;
243 }
244
245 pui_error
246 pui_display_manual_render_set(pui_h handle, pui_bool set)
247 {
248         pui_ani_h ani_h = NULL;
249
250         if (!handle)
251         {
252                 pui_err("Error : PUI_ERROR_INVALID_HANDLE\n");
253                 return PUI_ERROR_INVALID_HANDLE;
254         }
255
256         ani_h = handle->current_ani_h;
257
258         if (ani_h)
259         {
260                 if (pui_ani_status_get(ani_h->ani) == PUI_ANI_STATUS_RUNNING ||
261                         pui_ani_status_get(ani_h->ani) == PUI_ANI_STATUS_PAUSED)
262                 {
263                         pui_err("Please stop the current animation.\n");
264                         return PUI_ERROR_UNABLE_SET_MANUAL_RENDER;
265                 }
266         }
267
268         handle->manual_render = !!set;
269
270         return PUI_ERROR_NONE;
271 }
272
273 pui_bool
274 pui_display_manual_render_get(pui_h handle)
275 {
276         if (!handle)
277         {
278                 pui_err("Error : PUI_ERROR_INVALID_HANDLE\n");
279                 return 0;
280         }
281
282         return handle->manual_render;
283 }
284
285 pui_bool
286 pui_display_geometry_get(pui_h handle, int *width, int *height)
287 {
288         if (!width || !height)
289                 return 0;
290
291         *width = 0;
292         *height = 0;
293
294         if (!pui_module || !pui_module->backend_module_data) {
295                 pui_err("pui module data is not loaded\n");
296                 return 0;
297         }
298
299         if (!pui_module->backend_module_data->geometry_get)
300         {
301                 pui_err("Backend doesn't have geometry_get() !\n");
302                 return 0;
303         }
304
305         return pui_module->backend_module_data->geometry_get(width, height);
306 }
307
308 pui_h
309 pui_create(Ecore_Wl2_Window *win)
310 {
311         pui_h handle = NULL;
312         Ecore_Wl2_Display *ewd = ecore_wl2_window_display_get(win);
313         struct wayland_tbm_client *wl_tbm_client = NULL;
314
315         if (!win || !ewd)
316         {
317                 pui_err("Invalid window or display !\n");
318                 return NULL;
319         }
320
321         wl_tbm_client = wayland_tbm_client_init(ecore_wl2_display_get(ewd));
322
323         if (!wl_tbm_client)
324         {
325                 pui_err("Failed to init wayland_tbm_client !\n");
326                 return NULL;
327         }
328
329         handle = (pui_h)calloc(1, sizeof(pui));
330
331         if (!handle)
332                 return NULL;
333
334         handle->win = win;
335         handle->ewd = ewd;
336         handle->visibility = 0;
337         handle->wl_tbm_client = wl_tbm_client;
338         handle->ani_handles = NULL;
339         handle->current_ani_h = NULL;
340         handle->manual_render = 0;
341         handle->backend_module_data = pui_module->backend_module_data;
342
343         handle->tbm_queue = wayland_tbm_client_create_surface_queue(handle->wl_tbm_client,
344                                                                 ecore_wl2_window_surface_get(handle->win),
345                                                                 3, 100, 100, TBM_FORMAT_ABGR8888);
346
347         if (!handle->tbm_queue)
348         {
349                 pui_err("Failed to create a surface queue !");
350                 goto err;
351         }
352
353         return handle;
354
355 err:
356         pui_destroy(handle);
357
358         return NULL;
359 }
360
361 void
362 pui_destroy(pui_h handle)
363 {
364         pui_ani_h ani_h = NULL;
365
366         if (!handle)
367                 return;
368
369         EINA_LIST_FREE(handle->ani_handles, ani_h)
370         {
371                 pui_ani_destroy(ani_h);
372         }
373
374         if (handle->tbm_queue)
375         {
376                 tbm_surface_queue_destroy(handle->tbm_queue);
377         }
378
379         if (handle->wl_tbm_client)
380         {
381                 wayland_tbm_client_deinit(handle->wl_tbm_client);
382                 handle->wl_tbm_client = NULL;
383         }
384
385         free(handle);
386 }
387
388 #define PREFIX_LIB    "libpui-"
389 #define SUFFIX_LIB    ".so"
390 #define DEFAULT_LIB   PREFIX_LIB"default-backend"SUFFIX_LIB
391
392 static void
393 _pui_load_backend_module(void)
394 {
395         //char path[PATH_MAX] = {0, };
396         void *module_info = NULL;
397         pui_backend_module *backend_module_info = NULL;
398         int backend_module_major, backend_module_minor;
399         int pui_backend_major, pui_backend_minor;
400
401         pui_backend_module_data *backend_module_data = NULL;
402
403
404         module_info = dlopen(DEFAULT_LIB, RTLD_LAZY);
405
406         if (!module_info)
407         {
408                 pui_err("Failed to dlopen(error:%s, path:%s) !\n", dlerror(), DEFAULT_LIB);
409                 return;
410         }
411
412         backend_module_info = dlsym(module_info, "pui_backend_module_info");
413
414         if (!backend_module_info) {
415                 pui_err("Backend module(%s) doesn't have pui_backend_module_info !\n", DEFAULT_LIB);
416                 goto err;
417         }
418
419         pui_backend_major = PUI_BACKEND_GET_ABI_MAJOR(PUI_BACKEND_AB_VERSION_LAST);
420         pui_backend_minor = PUI_BACKEND_GET_ABI_MINOR(PUI_BACKEND_AB_VERSION_LAST);
421
422         backend_module_major = PUI_BACKEND_GET_ABI_MAJOR(backend_module_info->abi_version);
423         backend_module_minor = PUI_BACKEND_GET_ABI_MINOR(backend_module_info->abi_version);
424
425         if (backend_module_major > pui_backend_major) {
426                 pui_err("PUI backend module ABI major ver(%d) is newer than the PUI's ver(%d)\n",
427                         backend_module_major, pui_backend_major);
428                 goto err;
429         } else if (backend_module_minor > pui_backend_minor) {
430                 pui_err("PUI backend module ABI minor ver(%d) is newer than the PUI's ver(%d)\n",
431                         backend_module_minor, pui_backend_minor);
432                 goto err;
433         }
434
435         if (!backend_module_info->backend_init || !backend_module_info->backend_deinit)
436         {
437                 pui_err("Backend module doesn't have backend_init/backend_deinit function !\n");
438                 goto err;
439         }
440
441         backend_module_data = backend_module_info->backend_init();
442
443         if (!backend_module_data)
444         {
445                 pui_err("Failed to init module (%s) !\n", DEFAULT_LIB);
446                 goto err;
447         }
448
449         pui_module->module_info = module_info;
450         pui_module->backend_module_info = backend_module_info;
451         pui_module->backend_module_data = backend_module_data;
452
453         return;
454
455 err:
456         if (backend_module_info && backend_module_info->backend_deinit)
457                 backend_module_info->backend_deinit(backend_module_data);
458
459         if (module_info)
460                 dlclose(module_info);
461
462         return;
463 }
464
465 static void
466 _pui_unload_backend_module(void)
467 {
468         if (!pui_module)
469         {
470                 pui_err("Invalid pui module !\n");
471                 return;
472         }
473
474         if (pui_module->backend_module_info)
475         {
476                 pui_module->backend_module_info->backend_deinit(pui_module->backend_module_data);
477                 pui_module->backend_module_data = NULL;
478                 pui_module->backend_module_info = NULL;
479         }
480
481         if (pui_module->module_info)
482                 dlclose(pui_module->module_info);
483 }
484
485 static void
486 _pui_load_backend_collect_animations(void)
487 {
488         pui_int_error ret;
489
490         if (!pui_module || !pui_module->backend_module_data) {
491                 pui_err("pui module data is not loaded\n");
492                 return;
493         }
494
495         if (!pui_module->backend_module_data->create_ani_collection)
496         {
497                 pui_err("Backend doesn't have create_ani_collection() !\n");
498                 return;
499         }
500
501         ret = pui_module->backend_module_data->create_ani_collection();
502         if (ret != PUI_INT_ERROR_NONE) {
503                 pui_err("Failed to collect animations data (%s)\n",
504                         pui_error_to_string(ret));
505         }
506 }
507
508 static void
509 _pui_load(void)
510 {
511         _pui_load_backend_module();
512         _pui_load_backend_collect_animations();
513 }
514
515 static void
516 _pui_unload(void)
517 {
518         _pui_unload_backend_module();
519 }
520
521 static void
522 _pui_event_init(void)
523 {
524         PUI_EVENT_ANI_STARTED = ecore_event_type_new();
525         PUI_EVENT_ANI_STOPPED = ecore_event_type_new();
526         PUI_EVENT_ANI_PAUSED = ecore_event_type_new();
527         PUI_EVENT_ANI_READY_TO_START = ecore_event_type_new();
528         PUI_EVENT_ANI_READY_TO_RESUME = ecore_event_type_new();
529 }
530
531 static void
532 _pui_event_shutdown(void)
533 {
534         ecore_event_type_flush(PUI_EVENT_ANI_STARTED,
535                                         PUI_EVENT_ANI_STOPPED,
536                                         PUI_EVENT_ANI_PAUSED,
537                                         PUI_EVENT_ANI_READY_TO_START,
538                                         PUI_EVENT_ANI_READY_TO_RESUME);
539
540         PUI_EVENT_ANI_STARTED = -1;
541         PUI_EVENT_ANI_STOPPED = -1;
542         PUI_EVENT_ANI_PAUSED = -1;
543         PUI_EVENT_ANI_READY_TO_START = -1;
544         PUI_EVENT_ANI_READY_TO_RESUME = -1;
545 }
546
547 int
548 pui_init(void)
549 {
550         const char *cp = NULL;
551
552         if (++_pui_init_count != 1)
553           return _pui_init_count;
554
555         _pui_log_level = PUI_LOG_LEVEL_DEBUG;
556
557         cp = getenv("LIBPUI_LOG_LEVEL");
558
559         if (cp)
560         {
561                 _pui_log_level = atoi(cp);
562         }
563
564         if (pui_module)
565         {
566                 pui_err("Invalid calling of pui_init() !\n");
567                 goto error;
568         }
569
570         pui_module = (pui_module_data *)calloc(1, sizeof(pui_module_data));
571
572         if (!pui_module)
573         {
574                 pui_err("Failed to allocate memory for pui module data !\n");
575                 goto error;
576         }
577
578         ecore_wl2_init();
579
580         _pui_event_init();
581
582         _pui_load();
583
584         return _pui_init_count;
585
586 error:
587         return --_pui_init_count;
588 }
589
590 int
591 pui_shutdown(void)
592 {
593         if (_pui_init_count <= 0)
594         {
595                 pui_err("Invalid pui init count : %d\n", _pui_init_count);
596                 _pui_init_count = 0;
597                 return 0;
598         }
599
600         if (!pui_module)
601         {
602                 pui_err("Invalid pui module data !\n");
603                 return _pui_init_count;
604         }
605
606         _pui_init_count--;
607
608         //TODO
609         _pui_unload();
610
611         _pui_event_shutdown();
612
613         ecore_wl2_shutdown();
614
615         free(pui_module);
616
617         return _pui_init_count;
618 }
619