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