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