PUI: fix comment about abort() in magic failure function
[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 static const char *
52 _pui_magic_string_get(PUI_Magic m)
53 {
54         switch (m)
55         {
56                 case PUI_MAGIC_NONE:
57                         return "None (Freed Object)";
58                         break;
59
60                 case PUI_MAGIC_PUI_M:
61                         return "PUI MODULE (PUI_M)";
62                         break;
63
64                 case PUI_MAGIC_PUI_H:
65                         return "PUI HANDLE (PUI_H)";
66                         break;
67
68                 case PUI_MAGIC_ANI_H:
69                         return "PUI ANI HANDLE (ANI_H)";
70                         break;
71
72                 case PUI_MAGIC_ANI_T:
73                         return "PUI ANI RUNTIME HANDLE (ANI_T)";
74                         break;
75
76                 default:
77                         return "<Unknown>";
78         }
79 }
80
81 PUI_API void
82 _pui_magic_fail(const void *p, PUI_Magic m, PUI_Magic req_m, const char *fname)
83 {
84         pui_err(" ### PUI ERROR : PUI Magic Check Failed !!! in %s().\n", fname);
85
86         if (!p)
87                 pui_err("   Given handle/pointer is NULL !\n");
88         else if (m == PUI_MAGIC_NONE)
89                 pui_err("   Given handle/pointer has been freed !\n");
90         else if (m != req_m)
91                 pui_err("   Given handle/pointer is wrong type\n"
92                                 "      Expected: %08x - %s\n"
93                                 "      Supplied: %08x - %s",
94                                 (unsigned int)req_m, _pui_magic_string_get(req_m),
95                                 (unsigned int)m, _pui_magic_string_get(m));
96
97         /* abort here as a failure of magic can be caused by a memory corruption */
98         pui_err("### PUI MAGIC FAILED ! Abort ! ###\n");
99         abort();
100 }
101
102 pui_error_string
103 pui_error_to_string(pui_error e)
104 {
105         pui_error_string str = NULL;
106
107         switch (e)
108         {
109                 case PUI_ERROR_NONE:
110                         str = "PUI_No_Error";
111                         break;
112
113                 case PUI_ERROR_INVALID_ANI_HANDLE:
114                         str = "PUI_Invalid_Animation_Handle";
115                         break;
116
117                 case PUI_ERROR_INVALID_ANI_CMD:
118                         str = "PUI_Invalid_Animation_Command";
119                         break;
120
121                 case PUI_ERROR_INTERNAL:
122                         str = "PUI_Internal_Error";
123                         break;
124
125                 case PUI_ERROR_MANUAL_RENDER_ENABLED:
126                         str = "PUI_Manual_Render_Enabled";
127                         break;
128
129                 case PUI_ERROR_UNABLE_SET_MANUAL_RENDER:
130                         str = "PUI_Unable_To_Set_Manual_Render";
131                         break;
132
133                 default:
134                         str = "PUI_Unknown_Error";
135         }
136
137         return str;
138 }
139
140 static void
141 _buffer_release(void *data, struct wl_buffer *buffer)
142 {
143         tbm_surface_h surface = (tbm_surface_h)data;
144         pui_h handle;
145
146         tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_CLIENT, (void **)&handle);
147         tbm_surface_queue_release(handle->tbm_queue, surface);
148
149         pui_info("[UPDATE] release wl_buffer:%p, surface:%p\n", buffer, surface);
150 }
151
152 static const struct wl_buffer_listener buffer_listener = {
153     _buffer_release
154 };
155
156 pui_ani_control_buffer *
157 pui_display_get_buffer(pui_h handle)
158 {
159         tbm_surface_error_e ret;
160         tbm_surface_h surface;
161         pui_ani_control_buffer *buffer = NULL;
162
163         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
164         {
165                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
166                 return NULL;
167         }
168
169         if (handle->current_surface)
170         {
171                 pui_debug("[GET BUFFER] Current_surface is not used !\n");
172         }
173
174         if (!tbm_surface_queue_can_dequeue(handle->tbm_queue, 0))
175         {
176                 pui_err("[GET BUFFER] Failed to dequeue a tbm_surface !\n");
177                 return NULL;
178         }
179
180         ret = tbm_surface_queue_dequeue(handle->tbm_queue, &surface);
181
182         if (ret != TBM_SURFACE_ERROR_NONE)
183         {
184                 pui_err("[GET BUFFER] Dequeue err:%d\n", ret);
185                 return NULL;
186         }
187
188         tbm_surface_map(surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &handle->current_sinfo);
189
190         handle->current_surface = surface;
191         buffer = (pui_ani_control_buffer *)&(handle->current_sinfo.planes[0]);
192
193         return buffer;
194 }
195
196 pui_error
197 pui_display_set_buffer(pui_h handle, pui_ani_control_buffer *buffer)
198 {
199         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
200         {
201                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
202                 return PUI_ERROR_INVALID_HANDLE;
203         }
204
205         if (!handle->current_surface)
206         {
207                 pui_err("Current_surface is not valid !\n");
208                 return PUI_ERROR_INVALID_SURFACE;
209         }
210
211         if (!buffer || !buffer->ptr || !buffer->size)
212                 return PUI_ERROR_INVALID_BUFFER;
213
214         handle->is_buffer_set = 1;
215
216         return PUI_ERROR_NONE;
217 }
218
219 pui_error
220 pui_display_update(pui_h handle)
221 {
222         tbm_surface_h surface;
223         tbm_surface_error_e ret;
224         struct wl_buffer *wl_buffer = NULL;
225
226         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
227         {
228                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
229                 return PUI_ERROR_INVALID_HANDLE;
230         }
231
232         if (!handle->current_surface)
233                 return PUI_ERROR_INVALID_SURFACE;
234
235         if (!handle->is_buffer_set)
236         {
237                 pui_err("[UPDATE] Buffer is not set !\n");
238                 return PUI_ERROR_INVALID_BUFFER;
239         }
240
241         surface = handle->current_surface;
242         handle->current_surface = NULL;
243
244         tbm_surface_unmap(surface);
245
246         ret = tbm_surface_queue_enqueue(handle->tbm_queue, surface);
247
248         if (ret != TBM_SURFACE_ERROR_NONE)
249         {
250                 pui_err("[UPDATE] enqueue err:%d\n", ret);
251                 return PUI_ERROR_INVALID_SURFACE;
252         }
253
254         ret = tbm_surface_queue_acquire(handle->tbm_queue, &surface);
255
256         if (ret != TBM_SURFACE_ERROR_NONE)
257         {
258                 pui_err("[UPDATE] acquire err:%d\n", ret);
259                 return PUI_ERROR_INVALID_SURFACE;
260         }
261
262         if (!tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_WL_BUFFER, (void **)&wl_buffer)) {
263                 wl_buffer = wayland_tbm_client_create_buffer(handle->wl_tbm_client, surface);
264
265                 if (!wl_buffer)
266                 {
267                         pui_err("[UPDATE] failed to create wl_buffer tbm_surface:%p\n", surface);
268                         return PUI_ERROR_INVALID_BUFFER;
269                 }
270
271                 wl_buffer_add_listener(wl_buffer, &buffer_listener, surface);
272
273                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_WL_BUFFER, NULL);
274                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_WL_BUFFER, wl_buffer);
275                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_CLIENT, NULL);
276                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_CLIENT, handle);
277         }
278
279         if (!wl_buffer)
280         {
281                 pui_err("[UPDATE] dequeue err:%d\n", ret);
282                 return PUI_ERROR_INVALID_BUFFER;
283         }
284
285         ecore_wl2_window_buffer_attach(handle->win, wl_buffer, 0, 0, 0);
286         ecore_wl2_window_damage(handle->win, NULL, 0);
287         ecore_wl2_window_commit(handle->win, EINA_TRUE);
288
289         pui_info("[UPDATE] commit wl_buffer:%p, surface:%p\n", wl_buffer, surface);
290
291         handle->is_buffer_set = 0;
292
293         return PUI_ERROR_NONE;
294 }
295
296 pui_error
297 pui_display_manual_render_set(pui_h handle, pui_bool set)
298 {
299         pui_ani_h ani_h = NULL;
300
301         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
302         {
303                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
304                 return PUI_ERROR_INVALID_HANDLE;
305         }
306
307         ani_h = handle->current_ani_h;
308
309         if (ani_h)
310         {
311                 if (pui_ani_status_get(ani_h->ani) == PUI_ANI_STATUS_RUNNING ||
312                         pui_ani_status_get(ani_h->ani) == PUI_ANI_STATUS_PAUSED)
313                 {
314                         pui_err("Please stop the current animation.\n");
315                         return PUI_ERROR_UNABLE_SET_MANUAL_RENDER;
316                 }
317         }
318
319         handle->manual_render = !!set;
320
321         return PUI_ERROR_NONE;
322 }
323
324 pui_bool
325 pui_display_manual_render_get(pui_h handle)
326 {
327         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
328         {
329                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
330                 return 0;
331         }
332
333         return handle->manual_render;
334 }
335
336 pui_bool
337 pui_display_geometry_get(pui_h handle, int *width, int *height)
338 {
339         if (!width || !height)
340                 return 0;
341
342         *width = 0;
343         *height = 0;
344         (void) handle;
345
346         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
347         {
348                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
349                 return 0;
350         }
351
352         if (!pui_module->backend_module_data) {
353                 pui_err("pui module data is not loaded\n");
354                 return 0;
355         }
356
357         if (!pui_module->backend_module_data->geometry_get)
358         {
359                 pui_err("Backend doesn't have geometry_get() !\n");
360                 return 0;
361         }
362
363         return pui_module->backend_module_data->geometry_get(width, height);
364 }
365
366 pui_h
367 pui_create(Ecore_Wl2_Window *win)
368 {
369         pui_h handle = NULL;
370         Ecore_Wl2_Display *ewd = ecore_wl2_window_display_get(win);
371         struct wayland_tbm_client *wl_tbm_client = NULL;
372
373         if (!win || !ewd)
374         {
375                 pui_err("Invalid window or display !\n");
376                 return NULL;
377         }
378
379         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
380         {
381                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
382                 return NULL;
383         }
384
385         wl_tbm_client = wayland_tbm_client_init(ecore_wl2_display_get(ewd));
386
387         if (!wl_tbm_client)
388         {
389                 pui_err("Failed to init wayland_tbm_client !\n");
390                 return NULL;
391         }
392
393         handle = (pui_h)calloc(1, sizeof(pui));
394
395         if (!handle)
396                 return NULL;
397
398         handle->win = win;
399         handle->ewd = ewd;
400         handle->visibility = 0;
401         handle->wl_tbm_client = wl_tbm_client;
402         handle->ani_handles = NULL;
403         handle->current_ani_h = NULL;
404         handle->manual_render = 0;
405         handle->backend_module_data = pui_module->backend_module_data;
406
407         handle->tbm_queue = wayland_tbm_client_create_surface_queue(handle->wl_tbm_client,
408                                                                 ecore_wl2_window_surface_get(handle->win),
409                                                                 3, 100, 100, TBM_FORMAT_ABGR8888);
410
411         if (!handle->tbm_queue)
412         {
413                 pui_err("Failed to create a surface queue !");
414                 goto err;
415         }
416
417         PUI_MAGIC_SET(handle, PUI_MAGIC_PUI_H);
418         return handle;
419
420 err:
421         pui_destroy(handle);
422
423         return NULL;
424 }
425
426 void
427 pui_destroy(pui_h handle)
428 {
429         pui_ani_h ani_h = NULL;
430
431         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
432         {
433                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
434                 return;
435         }
436
437         EINA_LIST_FREE(handle->ani_handles, ani_h)
438         {
439                 pui_ani_destroy(ani_h);
440         }
441
442         if (handle->tbm_queue)
443         {
444                 tbm_surface_queue_destroy(handle->tbm_queue);
445         }
446
447         if (handle->wl_tbm_client)
448         {
449                 wayland_tbm_client_deinit(handle->wl_tbm_client);
450                 handle->wl_tbm_client = NULL;
451         }
452
453         PUI_MAGIC_SET(handle, PUI_MAGIC_NONE);
454         free(handle);
455 }
456
457 #define PREFIX_LIB    "libpui-"
458 #define SUFFIX_LIB    ".so"
459 #define DEFAULT_LIB   PREFIX_LIB"default-backend"SUFFIX_LIB
460
461 static void
462 _pui_load_backend_module(void)
463 {
464         //char path[PATH_MAX] = {0, };
465         void *module_info = NULL;
466         pui_backend_module *backend_module_info = NULL;
467         int backend_module_major, backend_module_minor;
468         int pui_backend_major, pui_backend_minor;
469
470         pui_backend_module_data *backend_module_data = NULL;
471
472         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
473         {
474                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
475                 return;
476         }
477
478         module_info = dlopen(DEFAULT_LIB, RTLD_LAZY);
479
480         if (!module_info)
481         {
482                 pui_err("Failed to dlopen(error:%s, path:%s) !\n", dlerror(), DEFAULT_LIB);
483                 return;
484         }
485
486         backend_module_info = dlsym(module_info, "pui_backend_module_info");
487
488         if (!backend_module_info) {
489                 pui_err("Backend module(%s) doesn't have pui_backend_module_info !\n", DEFAULT_LIB);
490                 goto err;
491         }
492
493         pui_backend_major = PUI_BACKEND_GET_ABI_MAJOR(PUI_BACKEND_AB_VERSION_LAST);
494         pui_backend_minor = PUI_BACKEND_GET_ABI_MINOR(PUI_BACKEND_AB_VERSION_LAST);
495
496         backend_module_major = PUI_BACKEND_GET_ABI_MAJOR(backend_module_info->abi_version);
497         backend_module_minor = PUI_BACKEND_GET_ABI_MINOR(backend_module_info->abi_version);
498
499         if (backend_module_major > pui_backend_major) {
500                 pui_err("PUI backend module ABI major ver(%d) is newer than the PUI's ver(%d)\n",
501                         backend_module_major, pui_backend_major);
502                 goto err;
503         } else if (backend_module_minor > pui_backend_minor) {
504                 pui_err("PUI backend module ABI minor ver(%d) is newer than the PUI's ver(%d)\n",
505                         backend_module_minor, pui_backend_minor);
506                 goto err;
507         }
508
509         if (!backend_module_info->backend_init || !backend_module_info->backend_deinit)
510         {
511                 pui_err("Backend module doesn't have backend_init/backend_deinit function !\n");
512                 goto err;
513         }
514
515         backend_module_data = backend_module_info->backend_init();
516
517         if (!backend_module_data)
518         {
519                 pui_err("Failed to init module (%s) !\n", DEFAULT_LIB);
520                 goto err;
521         }
522
523         pui_module->module_info = module_info;
524         pui_module->backend_module_info = backend_module_info;
525         pui_module->backend_module_data = backend_module_data;
526
527         return;
528
529 err:
530         if (backend_module_info && backend_module_info->backend_deinit)
531                 backend_module_info->backend_deinit(backend_module_data);
532
533         if (module_info)
534                 dlclose(module_info);
535
536         return;
537 }
538
539 static void
540 _pui_unload_backend_module(void)
541 {
542         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
543         {
544                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
545                 return;
546         }
547
548         if (pui_module->backend_module_info)
549         {
550                 pui_module->backend_module_info->backend_deinit(pui_module->backend_module_data);
551                 pui_module->backend_module_data = NULL;
552                 pui_module->backend_module_info = NULL;
553         }
554
555         if (pui_module->module_info)
556                 dlclose(pui_module->module_info);
557 }
558
559 static void
560 _pui_load_backend_collect_animations(void)
561 {
562         pui_int_error ret;
563
564         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
565         {
566                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
567                 return;
568         }
569
570         if (!pui_module->backend_module_data) {
571                 pui_err("pui module data is not loaded\n");
572                 return;
573         }
574
575         if (!pui_module->backend_module_data->create_ani_collection)
576         {
577                 pui_err("Backend doesn't have create_ani_collection() !\n");
578                 return;
579         }
580
581         ret = pui_module->backend_module_data->create_ani_collection();
582         if (ret != PUI_INT_ERROR_NONE) {
583                 pui_err("Failed to collect animations data (%s)\n",
584                         pui_error_to_string(ret));
585         }
586 }
587
588 static void
589 _pui_load(void)
590 {
591         _pui_load_backend_module();
592         _pui_load_backend_collect_animations();
593 }
594
595 static void
596 _pui_unload(void)
597 {
598         _pui_unload_backend_module();
599 }
600
601 static void
602 _pui_event_init(void)
603 {
604         PUI_EVENT_ANI_STARTED = ecore_event_type_new();
605         PUI_EVENT_ANI_STOPPED = ecore_event_type_new();
606         PUI_EVENT_ANI_PAUSED = ecore_event_type_new();
607         PUI_EVENT_ANI_READY_TO_START = ecore_event_type_new();
608         PUI_EVENT_ANI_READY_TO_RESUME = ecore_event_type_new();
609 }
610
611 static void
612 _pui_event_shutdown(void)
613 {
614         ecore_event_type_flush(PUI_EVENT_ANI_STARTED,
615                                         PUI_EVENT_ANI_STOPPED,
616                                         PUI_EVENT_ANI_PAUSED,
617                                         PUI_EVENT_ANI_READY_TO_START,
618                                         PUI_EVENT_ANI_READY_TO_RESUME);
619
620         PUI_EVENT_ANI_STARTED = -1;
621         PUI_EVENT_ANI_STOPPED = -1;
622         PUI_EVENT_ANI_PAUSED = -1;
623         PUI_EVENT_ANI_READY_TO_START = -1;
624         PUI_EVENT_ANI_READY_TO_RESUME = -1;
625 }
626
627 int
628 pui_init(void)
629 {
630         const char *cp = NULL;
631
632         if (++_pui_init_count != 1)
633           return _pui_init_count;
634
635         _pui_log_level = PUI_LOG_LEVEL_DEBUG;
636
637         cp = getenv("LIBPUI_LOG_LEVEL");
638
639         if (cp)
640         {
641                 _pui_log_level = atoi(cp);
642         }
643
644         if (pui_module)
645         {
646                 pui_err("Invalid calling of pui_init() !\n");
647                 goto error;
648         }
649
650         pui_module = (pui_module_data *)calloc(1, sizeof(pui_module_data));
651
652         if (!pui_module)
653         {
654                 pui_err("Failed to allocate memory for pui module data !\n");
655                 goto error;
656         }
657
658         PUI_MAGIC_SET(pui_module, PUI_MAGIC_PUI_M);
659
660         ecore_wl2_init();
661
662         _pui_event_init();
663
664         _pui_load();
665
666         return _pui_init_count;
667
668 error:
669         return --_pui_init_count;
670 }
671
672 int
673 pui_shutdown(void)
674 {
675         if (_pui_init_count <= 0)
676         {
677                 pui_err("Invalid pui init count : %d\n", _pui_init_count);
678                 _pui_init_count = 0;
679                 return 0;
680         }
681
682         if (!PUI_MAGIC_CHECK(pui_module, PUI_MAGIC_PUI_M))
683         {
684                 PUI_MAGIC_FAIL(pui_module, PUI_MAGIC_PUI_M, __FUNCTION__);
685                 return _pui_init_count;
686         }
687
688         _pui_init_count--;
689
690         //TODO
691         _pui_unload();
692
693         _pui_event_shutdown();
694
695         ecore_wl2_shutdown();
696
697         PUI_MAGIC_SET(pui_module, PUI_MAGIC_NONE);
698         free(pui_module);
699
700         return _pui_init_count;
701 }
702