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