Update AUTHORS and boiler plates
[platform/core/uifw/libpui.git] / src / PUI_ani.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 #include <Eina.h>
30
31 static int KEY_WL_BUFFER = 0xabcdbeaf;
32 static int KEY_CLIENT = 0xdcbabeaf;
33
34 static Eina_Bool
35 _cb_window_show(void *data, int type EINA_UNUSED, void *event)
36 {
37         pui_ani_h handle =  (pui_ani_h)data;
38         Ecore_Wl2_Event_Window_Show *ev = (Ecore_Wl2_Event_Window_Show *)event;
39
40         pui_info("...\n");
41
42         /* TODO */
43         (void) handle;
44         (void) ev;
45
46         return ECORE_CALLBACK_PASS_ON;
47 }
48
49 static Eina_Bool
50 _cb_focus_in(void *data, int type EINA_UNUSED, void *event)
51 {
52         pui_ani_h handle =  (pui_ani_h)data;
53         Ecore_Wl2_Event_Focus_In *ev = (Ecore_Wl2_Event_Focus_In *)event;
54
55         pui_info("...\n");
56
57         /* TODO */
58         (void) handle;
59         (void) ev;
60
61         return ECORE_CALLBACK_PASS_ON;
62 }
63
64 static Eina_Bool
65 _cb_focus_out(void *data, int type EINA_UNUSED, void *event)
66 {
67         pui_ani_h handle =  (pui_ani_h)data;
68         Ecore_Wl2_Event_Focus_Out *ev = (Ecore_Wl2_Event_Focus_Out *)event;
69
70         pui_info("...\n");
71
72         /* TODO */
73         (void) handle;
74         (void) ev;
75
76         return ECORE_CALLBACK_PASS_ON;
77 }
78
79 static Eina_Bool
80 _cb_visibility_change(void *data, int type EINA_UNUSED, void *event)
81 {
82         pui_ani_h ani_h =  (pui_ani_h)data;
83         pui_ani_t *ani = ani_h->ani;
84         pui_h ph = ani_h->pui_handle;
85
86         Ecore_Wl2_Event_Window_Visibility_Change *ev;
87         PUI_Event_Animation_Status *e = NULL;
88
89         ev = event;
90
91         pui_info("Visibility change (window=0x%x, fully_obscured=%d)\n", ev->win, ev->fully_obscured);
92
93         /* check if this is needed */
94         ph->visibility = !(ev->fully_obscured);
95
96         if (ev->fully_obscured)
97         {
98                 if (ani->status == PUI_ANI_STATUS_RUNNING)
99                 {
100                         ani->status = PUI_ANI_STATUS_STOPPED;
101
102                         e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
103
104                         if (!e)
105                         {
106                                 pui_err("Failed to allocate memory for PUI Event !\n");
107                                 return ECORE_CALLBACK_PASS_ON;
108                         }
109                         
110                         e->win = ev->win;
111                         e->status = PUI_ANI_STATUS_FORCE_STOPPED;
112                         
113                         ecore_event_add(PUI_EVENT_ANI_STOPPED, e, NULL, ani_h);
114                 }
115         }
116         else
117         {
118                 e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
119                 
120                 if (!e)
121                 {
122                         pui_err("Failed to allocate memory for PUI Event !\n");
123                         return ECORE_CALLBACK_PASS_ON;
124                 }
125                 
126                 e->win = ev->win;
127                 e->status = ani->status;
128                 
129                 if (ani->status == PUI_ANI_STATUS_STOPPED)
130                         ecore_event_add(PUI_EVENT_ANI_READY_TO_START, e, NULL, ani_h);
131                 else if(ani->status == PUI_ANI_STATUS_PAUSED)
132                         ecore_event_add(PUI_EVENT_ANI_READY_TO_RESUME, e, NULL, ani_h);
133         }
134
135         return ECORE_CALLBACK_PASS_ON;
136 }
137
138 static void
139 _pui_ani_cb_frame_done(Ecore_Wl2_Window *win, uint32_t timestamp EINA_UNUSED, void *data)
140 {
141         pui_h handle = (pui_h) data;
142
143         pui_info("Frame done ! (window=%p)\n", win);
144
145         // TODO
146         (void) handle;
147
148         return;
149 }
150
151 static void
152 _buffer_release(void *data, struct wl_buffer *buffer)
153 {
154         tbm_surface_h surface = (tbm_surface_h)data;
155         pui_h handle;
156
157         tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_CLIENT, (void **)&handle);
158         tbm_surface_queue_release(handle->tbm_queue, surface);
159
160         pui_info("[UPDATE] release wl_buffer:%p, surface:%p\n", buffer, surface);
161 }
162
163 static const struct wl_buffer_listener buffer_listener = {
164     _buffer_release
165 };
166
167 pui_ani_control_buffer *
168 pui_ani_get_buffer(pui_ani_h ani_h)
169 {
170         pui_h handle = NULL;
171         tbm_surface_error_e ret;
172         tbm_surface_h surface;
173         pui_ani_control_buffer *buffer = NULL;
174
175         if (!ani_h)
176         {
177                 pui_err("Invalid pui ani handle !\n");
178                 return NULL;
179         }
180
181         handle = ani_h->pui_handle;
182
183         if (!handle)
184         {
185                 pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
186                 return NULL;
187         }
188
189         if (handle->current_surface)
190         {
191                 pui_warn("Current_surface is not used !\n");
192         }
193
194         if (!tbm_surface_queue_can_dequeue(handle->tbm_queue, 0))
195         {
196                 pui_err("[UPDATE] Cannot dequeue (error : PUI_ERROR_INTERNAL)\n");
197                 return NULL;
198         }
199
200         ret = tbm_surface_queue_dequeue(handle->tbm_queue, &surface);
201
202         if (ret != TBM_SURFACE_ERROR_NONE)
203         {
204                 pui_err("[UPDATE] dequeue err:%d\n", ret);
205                 return NULL;
206         }
207
208         tbm_surface_map(surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &handle->current_sinfo);
209
210         handle->current_surface = surface;
211         buffer = (pui_ani_control_buffer *)&(handle->current_sinfo.planes[0]);
212
213         return buffer;
214 }
215
216 pui_int_error
217 pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer)
218 {
219         pui_h handle = NULL;
220
221         if (!ani_h)
222         {
223                 pui_err("Invalid ani handle !\n");
224                 return PUI_INT_ERROR_INVALID_HANDLE;
225         }
226
227         handle = ani_h->pui_handle;
228
229         if (!handle)
230         {
231                 pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
232                 return PUI_INT_ERROR_INVALID_HANDLE;
233         }
234
235         if (!handle->current_surface)
236         {
237                 pui_err("Current_surface is not valid !\n");
238                 return PUI_INT_ERROR_INVALID_SURFACE;
239         }
240
241         if (!buffer || !buffer->ptr || !buffer->size)
242                 return PUI_INT_ERROR_INVALID_BUFFER;
243
244         handle->is_buffer_set = 1;
245
246         return PUI_INT_ERROR_NONE;
247 }
248
249 pui_int_error
250 pui_ani_update(pui_ani_h ani_h)
251 {
252         tbm_surface_h surface;
253         tbm_surface_error_e ret;
254         struct wl_buffer *wl_buffer = NULL;
255
256         pui_h handle = NULL;
257
258         if (!ani_h)
259         {
260                 pui_err("Invalid ani handle !\n");
261                 return PUI_INT_ERROR_INVALID_HANDLE;
262         }
263
264         handle = ani_h->pui_handle;
265
266         if (!handle)
267         {
268                 pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
269                 return PUI_INT_ERROR_INVALID_HANDLE;
270         }
271
272         if (!handle->current_surface)
273                 return PUI_INT_ERROR_INVALID_SURFACE;
274
275         if (!handle->is_buffer_set)
276         {
277                 pui_err("Buffer is not set !\n");
278                 return PUI_INT_ERROR_INVALID_BUFFER;
279         }
280
281         surface = handle->current_surface;
282         handle->current_surface = NULL;
283
284         tbm_surface_unmap(surface);
285
286         ret = tbm_surface_queue_enqueue(handle->tbm_queue, surface);
287
288         if (ret != TBM_SURFACE_ERROR_NONE)
289         {
290                 pui_err("[UPDATE] enqueue err:%d\n", ret);
291                 return PUI_INT_ERROR_INVALID_SURFACE;
292         }
293
294         ret = tbm_surface_queue_acquire(handle->tbm_queue, &surface);
295
296         if (ret != TBM_SURFACE_ERROR_NONE)
297         {
298                 pui_err("[UPDATE] acquire err:%d\n", ret);
299                 return PUI_INT_ERROR_INVALID_SURFACE;
300         }
301
302         if (!tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_WL_BUFFER, (void **)&wl_buffer)) {
303                 wl_buffer = wayland_tbm_client_create_buffer(handle->wl_tbm_client, surface);
304
305                 if (!wl_buffer)
306                 {
307                         pui_err("[UPDATE] failed to create wl_buffer tbm_surface:%p\n", surface);
308                         return PUI_INT_ERROR_INVALID_BUFFER;
309                 }
310
311                 wl_buffer_add_listener(wl_buffer, &buffer_listener, surface);
312
313                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_WL_BUFFER, NULL);
314                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_WL_BUFFER, wl_buffer);
315                 tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_CLIENT, NULL);
316                 tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_CLIENT, handle);
317         }
318
319         if (!wl_buffer)
320         {
321                 pui_err("[UPDATE] dequeue err:%d\n", ret);
322                 return PUI_INT_ERROR_INVALID_BUFFER;
323         }
324
325         ecore_wl2_window_buffer_attach(handle->win, wl_buffer, 0, 0, 0);
326         ecore_wl2_window_damage(handle->win, NULL, 0);
327         ecore_wl2_window_commit(handle->win, EINA_TRUE);
328
329         pui_info("[UPDATE] commit wl_buffer:%p, surface:%p\n", wl_buffer, surface);
330
331         handle->is_buffer_set = 0;
332
333         return PUI_INT_ERROR_NONE;
334 }
335
336 static void
337 _pui_ani_event_handlers_init(pui_ani_h ani_h)
338 {
339         Ecore_Event_Handler *h = NULL;
340
341         if (!ani_h)
342         {
343                 pui_err("Invalid handle !\n");
344                 return;
345         }
346
347         if (!ani_h->ecore_event_hdls)
348                 ani_h->ecore_event_hdls = eina_array_new(5);
349
350         h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_SHOW, _cb_window_show, ani_h);
351         eina_array_push(ani_h->ecore_event_hdls, h);
352
353         h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_IN, _cb_focus_in, ani_h);
354         eina_array_push(ani_h->ecore_event_hdls, h);
355
356         h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_OUT, _cb_focus_out, ani_h);
357         eina_array_push(ani_h->ecore_event_hdls, h);
358
359         h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, ani_h);
360         eina_array_push(ani_h->ecore_event_hdls, h);
361
362 }
363
364 static void
365 _pui_ani_event_handlers_shutdown(pui_ani_h ani_h)
366 {
367         if (!ani_h)
368         {
369                 pui_err("Invalid handle !\n");
370                 return;
371         }
372
373         if (ani_h->ecore_event_hdls)
374         {
375                 while (eina_array_count(ani_h->ecore_event_hdls))
376                         ecore_event_handler_del(eina_array_pop(ani_h->ecore_event_hdls));
377
378                 eina_array_free(ani_h->ecore_event_hdls);
379                 ani_h->ecore_event_hdls = NULL;
380         }
381 }
382
383 static Eina_Bool
384 _pui_ani_frame_cb(void *data)
385 {
386         Eina_Bool ret;
387
388         pui_ani_t *ani = (pui_ani_t *)data;
389
390         if (!ani)
391         {
392                 pui_err("Invalid pui ani !\n");
393                 return ECORE_CALLBACK_CANCEL;
394         }
395
396         if (!ani->backend_frame_cb)
397         {
398                 pui_err("Invalid backend frame_cb !\n");
399                 return ECORE_CALLBACK_CANCEL;
400         }
401
402         if (!ani->frame_cb_timer)
403         {
404                 pui_err("Invalid frame_cb timer !\n");
405                 return ECORE_CALLBACK_CANCEL;
406         }
407
408         pui_info("frame_cb !\n");
409
410         ret = (Eina_Bool)ani->backend_frame_cb(ani, ++ani->serial);
411
412         pui_ani_status_update(ani, PUI_ANI_STATUS_RUNNING);
413
414         return ret;
415 }
416
417 pui_bool
418 pui_ani_add_frame_cb(pui_ani_t *ani, pui_bool (*frame_cb)(void *data, int serial), double frame_interval)
419 {
420         Ecore_Timer *timer = NULL;
421
422         if (!ani)
423         {
424                 pui_err("Invalid put ani !\n");
425                 return 0;
426         }
427
428         ani->frame_cb = _pui_ani_frame_cb;
429         ani->backend_frame_cb = frame_cb;
430         ani->frame_interval = frame_interval;
431         ani->frame_cb_data = ani;
432         ani->serial = 0;
433
434         timer = ecore_timer_add(frame_interval, _pui_ani_frame_cb, ani);
435
436         if (!timer)
437         {
438                 pui_err("Failed to add ecore timer !\n");
439                 return 0;
440         }
441
442         ani->frame_cb_timer = timer;
443
444         /* call frame_cb for starting the first frame */
445         _pui_ani_frame_cb(ani);
446
447         return 1;
448 }
449
450 void
451 pui_ani_remove_frame_cb(pui_ani_t *ani)
452 {
453         if (!ani)
454                 return;
455
456         if (ani->frame_cb_timer)
457         {
458                 ecore_timer_del(ani->frame_cb_timer);
459                 ani->frame_cb_timer = NULL;
460         }
461
462         ani->frame_cb = NULL;
463         ani->backend_frame_cb = NULL;
464         ani->frame_interval = 0;
465         ani->frame_cb_data = NULL;
466 }
467
468 pui_id
469 pui_ani_get_id(pui_ani_h ani_h)
470 {
471         if (!ani_h || !ani_h->ani)
472                 return NULL;
473
474         return ani_h->ani->id;
475 }
476
477 pui_ani_cmd
478 pui_ani_get_cmd(pui_ani_h ani_h)
479 {
480         if (!ani_h || !ani_h->ani)
481                 return PUI_ANI_CMD_NONE;
482
483         return ani_h->ani->cmd;
484 }
485
486 int
487 pui_ani_get_repeat(pui_ani_h ani_h)
488 {
489         if (!ani_h || !ani_h->ani)
490                 return 0;
491
492         return ani_h->ani->repeat;
493 }
494
495 pui_backend_ani_data *
496 pui_ani_get_ani_data(pui_ani_t *ani)
497 {
498         if (!ani)
499                 return NULL;
500
501         return ani->ani_data;
502 }
503
504 void
505 pui_ani_status_update(pui_ani_t *ani, pui_ani_status status)
506 {
507         //TODO : add PUI EVENT
508
509         ani->status = status;
510 }
511
512 pui_ani_status
513 pui_ani_status_get(pui_ani_t *ani)
514 {
515         pui_ani_status status = PUI_ANI_STATUS_UNKNOWN;
516
517         if (!ani)
518         {
519                 pui_err("Invalid pui ani !\n");
520                 return status;
521         }
522
523         return ani->status;
524 }
525
526 pui_error
527 pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat)
528 {
529         pui_ani_t *ani = NULL;
530         pui_h handle = NULL;
531         pui_backend_ani_func *ani_func = NULL;
532
533         if (!ani_h)
534                 return PUI_ERROR_INVALID_ANI_HANDLE;
535
536         if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST)
537         {
538                 pui_err("Invalid cmd ! (repeat=%d)\n", repeat);
539                 return PUI_ERROR_INVALID_ANI_CMD;
540         }
541
542         if (repeat < -1)
543         {
544                 pui_err("Invalid repeat count ! (repeat=%d)\n", repeat);
545                 return PUI_ERROR_INVALID_ANI_REPEAT;
546         }
547
548         //TODO : check if there is any animation being played already
549         //NOTE : the id of the animation being played can be different from ani_h->id
550
551         handle = ani_h->pui_handle;
552         ani = ani_h->ani;
553
554         if (!ani || !ani->ani_data)
555         {
556                 pui_err("Invalid ani or ani_data !\n");
557                 return PUI_ERROR_INTERNAL;
558         }
559
560         ani_func = ani->ani_data->ani_func;
561
562         ani->cmd = cmd;
563         ani->repeat = repeat;
564
565         if (cmd == PUI_ANI_CMD_START)
566         {
567                 ani_func->ani_start(ani, repeat);
568         }
569         else//cmd == PUI_ANI_CMD_STOP
570         {
571                 ani_func->ani_stop(ani);
572                 return PUI_ERROR_NONE;
573         }
574
575         ani_h->frame_done_cb = ecore_wl2_window_frame_callback_add(handle->win, _pui_ani_cb_frame_done, handle);
576
577         if (!ani_h->frame_done_cb)
578         {
579                 pui_err("Failed to add frame callback !");
580                 goto err;
581         }
582
583         //TODO
584
585         return PUI_ERROR_NONE;
586
587 err:
588         return PUI_ERROR_INTERNAL;
589 }
590
591 pui_ani_h
592 pui_ani_create(pui_h handle, pui_id id)
593 {
594         pui_ani_h ani_h = NULL;
595         pui_ani_t *ani = NULL;
596         pui_backend_ani_data *ani_data = NULL;
597
598         if (!handle || !handle->backend_module_data)
599         {
600                 pui_err("Invalid pui handle or backend module data !\n");
601                 return NULL;
602         }
603
604         ani_data = handle->backend_module_data->ani_create(id);
605
606         if (!ani_data)
607         {
608                 pui_err("Invalid ani data from backend module data !\n");
609                 return NULL;
610         }
611
612         ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani));
613
614         if (!ani_h)
615         {
616                 pui_err("Failed to allocate memory for pui ani handle !\n");
617                 goto err;
618         }
619
620         ani_h->id = strdup(id);
621         ani_h->pui_handle = handle;
622         ani_h->ecore_event_hdls = NULL;
623
624         _pui_ani_event_handlers_init(ani_h);
625
626         ani = (pui_ani_t *)calloc(1, sizeof(pui_ani_t));
627
628         if (!ani)
629         {
630                 pui_err("Failed to allocate memory for pui ani mgr !\n");
631                 goto err;
632         }
633
634         ani->ani_h = ani_h;
635         ani->id = id;
636         ani->cmd = PUI_ANI_CMD_NONE;
637         ani->repeat = 0;
638         ani->status = PUI_ANI_STATUS_INITIAL;
639         ani->ani_data = ani_data;
640
641         ani_h->ani = ani;
642
643         handle->ani_handles = eina_list_append(handle->ani_handles, ani_h);
644
645         return ani_h;
646
647 err:
648         if (ani_data)
649         {
650                 handle->backend_module_data->ani_destroy(ani_data);
651         }
652
653         if (ani_h)
654                 free(ani_h);
655
656         return NULL;
657 }
658
659 void
660 pui_ani_destroy(pui_ani_h ani_h)
661 {
662         pui_h handle = NULL;
663         pui_ani_t *ani = NULL;
664         pui_backend_module_data *backend_module_data = NULL;
665
666         if (!ani_h || !ani_h->pui_handle)
667                 return;
668
669         handle = ani_h->pui_handle;
670         ani = ani_h->ani;
671
672         /* stop the animation being played already if any */
673         if (ani->status != PUI_ANI_STATUS_STOPPED)
674                 pui_ani_control(ani_h, PUI_ANI_CMD_STOP, 0);
675
676         backend_module_data = handle->backend_module_data;
677         backend_module_data->ani_destroy(ani->ani_data);
678         ani->ani_data = NULL;
679
680         if (ani->frame_cb_timer)
681         {
682                 ecore_timer_del(ani->frame_cb_timer);
683                 ani->frame_cb_timer = NULL;
684         }
685
686         free(ani_h->ani);
687
688         _pui_ani_event_handlers_shutdown(ani_h);
689
690         if (ani_h->frame_done_cb)
691         {
692                 ecore_wl2_window_frame_callback_del(ani_h->frame_done_cb);
693                 ani_h->frame_done_cb = NULL;
694         }
695
696         handle->ani_handles = eina_list_remove(handle->ani_handles, ani_h);
697
698         free(ani_h->id);
699         free(ani_h);
700 }
701