Update the H/W buffer support API
[apps/livebox/livebox.git] / src / livebox.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <errno.h>
19 #include <stdlib.h> /* malloc */
20 #include <string.h> /* strdup */
21 #include <libgen.h>
22
23 #include <dlog.h>
24 #include <livebox-service.h>
25 #include <provider.h>
26 #include <provider_buffer.h>
27
28 #include "debug.h"
29 #include "livebox.h"
30 #include "dlist.h"
31 #include "util.h"
32
33 #define EAPI __attribute__((visibility("default")))
34
35 #define FILE_SCHEMA     "file://"
36
37 /*!
38  * \brief This function is defined by the data-provider-slave
39  */
40 extern const char *livebox_find_pkgname(const char *filename);
41 extern int livebox_request_update_by_id(const char *uri);
42
43 struct block {
44         unsigned int idx;
45
46         char *type;
47         char *part;
48         char *data;
49         char *option;
50         char *id;
51         char *file;
52         char *target_id;
53 };
54
55 struct livebox_desc {
56         FILE *fp;
57         int for_pd;
58
59         unsigned int last_idx;
60
61         struct dlist *block_list;
62 };
63
64 struct livebox_buffer_data {
65         int is_pd;
66         int accelerated;
67 };
68
69 EAPI const int DONE = 0x00;
70 EAPI const int OUTPUT_UPDATED = 0x02;
71 EAPI const int USE_NET = 0x04;
72
73 EAPI const int NEED_TO_SCHEDULE = 0x01;
74 EAPI const int NEED_TO_CREATE = 0x01;
75 EAPI const int NEED_TO_DESTROY = 0x01;
76 EAPI const int NEED_TO_UPDATE = 0x01;
77
78 EAPI const int LB_SYS_EVENT_FONT_CHANGED = 0x01;
79 EAPI const int LB_SYS_EVENT_LANG_CHANGED = 0x02;
80 EAPI const int LB_SYS_EVENT_TIME_CHANGED = 0x04;
81 EAPI const int LB_SYS_EVENT_PAUSED = 0x0100;
82 EAPI const int LB_SYS_EVENT_RESUMED = 0x0200;
83
84 EAPI struct livebox_desc *livebox_desc_open(const char *filename, int for_pd)
85 {
86         struct livebox_desc *handle;
87         char *new_fname;
88
89         handle = calloc(1, sizeof(*handle));
90         if (!handle) {
91                 ErrPrint("Error: %s\n", strerror(errno));
92                 return NULL;
93         }
94
95         if (for_pd) {
96                 int len;
97                 len = strlen(filename) + strlen(".desc") + 1;
98                 new_fname = malloc(len);
99                 if (!new_fname) {
100                         ErrPrint("Error: %s\n", strerror(errno));
101                         free(handle);
102                         return NULL;
103                 }
104                 snprintf(new_fname, len, "%s.desc", filename);
105         } else {
106                 new_fname = strdup(filename);
107                 if (!new_fname) {
108                         ErrPrint("Error: %s\n", strerror(errno));
109                         free(handle);
110                         return NULL;
111                 }
112         }
113
114         DbgPrint("Open a new file: %s\n", new_fname);
115         handle->fp = fopen(new_fname, "w+t");
116         free(new_fname);
117         if (!handle->fp) {
118                 ErrPrint("Failed to open a file: %s\n", strerror(errno));
119                 free(handle);
120                 return NULL;
121         }
122
123         return handle;
124 }
125
126 EAPI int livebox_desc_close(struct livebox_desc *handle)
127 {
128         struct dlist *l;
129         struct dlist *n;
130         struct block *block;
131
132         if (!handle)
133                 return -EINVAL;
134
135         DbgPrint("Close and flush\n");
136         dlist_foreach_safe(handle->block_list, l, n, block) {
137                 handle->block_list = dlist_remove(handle->block_list, l);
138
139                 DbgPrint("{\n");
140                 fprintf(handle->fp, "{\n");
141                 if (block->type) {
142                         fprintf(handle->fp, "type=%s\n", block->type);
143                         DbgPrint("type=%s\n", block->type);
144                 }
145
146                 if (block->part) {
147                         fprintf(handle->fp, "part=%s\n", block->part);
148                         DbgPrint("part=%s\n", block->part);
149                 }
150
151                 if (block->data) {
152                         fprintf(handle->fp, "data=%s\n", block->data);
153                         DbgPrint("data=%s\n", block->data);
154                 }
155
156                 if (block->option) {
157                         fprintf(handle->fp, "option=%s\n", block->option);
158                         DbgPrint("option=%s\n", block->option);
159                 }
160
161                 if (block->id) {
162                         fprintf(handle->fp, "id=%s\n", block->id);
163                         DbgPrint("id=%s\n", block->id);
164                 }
165
166                 if (block->target_id) {
167                         fprintf(handle->fp, "target=%s\n", block->target_id);
168                         DbgPrint("target=%s\n", block->target_id);
169                 }
170
171                 fprintf(handle->fp, "}\n");
172                 DbgPrint("}\n");
173
174                 free(block->type);
175                 free(block->part);
176                 free(block->data);
177                 free(block->option);
178                 free(block->id);
179                 free(block->target_id);
180                 free(block);
181         }
182
183         fclose(handle->fp);
184         free(handle);
185         return 0;
186 }
187
188 EAPI int livebox_desc_set_category(struct livebox_desc *handle, const char *id, const char *category)
189 {
190         struct block *block;
191
192         if (!handle || !category)
193                 return -EINVAL;
194
195         block = calloc(1, sizeof(*block));
196         if (!block)
197                 return -ENOMEM;
198
199         block->type = strdup(LB_DESC_TYPE_INFO);
200         if (!block->type) {
201                 free(block);
202                 return -ENOMEM;
203         }
204
205         block->part = strdup("category");
206         if (!block->part) {
207                 free(block->type);
208                 free(block);
209                 return -ENOMEM;
210         }
211
212         block->data = strdup(category);
213         if (!block->data) {
214                 free(block->type);
215                 free(block->part);
216                 free(block);
217                 return -ENOMEM;
218         }
219
220         if (id) {
221                 block->id = strdup(id);
222                 if (!block->id) {
223                         free(block->data);
224                         free(block->type);
225                         free(block->part);
226                         free(block);
227                         return -ENOMEM;
228                 }
229         }
230
231         block->idx = handle->last_idx++;
232         handle->block_list = dlist_append(handle->block_list, block);
233         return block->idx;
234 }
235
236 EAPI int livebox_desc_set_size(struct livebox_desc *handle, const char *id, int w, int h)
237 {
238         struct block *block;
239         char buffer[BUFSIZ];
240
241         if (!handle)
242                 return -EINVAL;
243
244         block = calloc(1, sizeof(*block));
245         if (!block)
246                 return -ENOMEM;
247
248         block->type = strdup(LB_DESC_TYPE_INFO);
249         if (!block->type) {
250                 free(block);
251                 return -ENOMEM;
252         }
253
254         block->part = strdup("size");
255         if (!block->part) {
256                 free(block->type);
257                 free(block);
258                 return -ENOMEM;
259         }
260
261         if (id) {
262                 block->id = strdup(id);
263                 if (!block->id) {
264                         free(block->part);
265                         free(block->type);
266                         free(block);
267                         return -ENOMEM;
268                 }
269         }
270
271         snprintf(buffer, sizeof(buffer), "%dx%d", w, h);
272         block->data = strdup(buffer);
273         if (!block->data) {
274                 free(block->part);
275                 free(block->type);
276                 free(block);
277                 return -ENOMEM;
278         }
279
280         block->idx = handle->last_idx++;
281         handle->block_list = dlist_append(handle->block_list, block);
282         return block->idx;
283 }
284
285 EAPI char *livebox_util_nl2br(const char *str)
286 {
287         int len;
288         register int i;
289         char *ret;
290         char *ptr;
291
292         if (!str)
293                 return NULL;
294
295         len = strlen(str);
296         if (!len)
297                 return NULL;
298
299         ret = malloc(len + 1);
300         if (!ret)
301                 return NULL;
302
303         ptr = ret;
304         i = 0;
305         while (*str) {
306                 switch (*str) {
307                 case '\n':
308                         if (len - i < 5) {
309                                 char *tmp;
310                                 len += len;
311
312                                 tmp = realloc(ret, len + 1);
313                                 if (!tmp) {
314                                         free(ret);
315                                         return NULL;
316                                 }
317
318                                 ret = tmp;
319                                 ptr = tmp + i;
320                         }
321
322                         strcpy(ptr, "<br>");
323                         ptr += 4;
324                         i += 4;
325                         break;
326                 default:
327                         *ptr++ = *str;
328                         i++;
329                         break;
330                 }
331
332                 str++;
333         }
334         *ptr = '\0';
335
336         return ret;
337 }
338
339 EAPI int livebox_desc_set_id(struct livebox_desc *handle, int idx, const char *id)
340 {
341         struct dlist *l;
342         struct block *block;
343
344         dlist_foreach(handle->block_list, l, block) {
345                 if (block->idx == idx) {
346                         if (strcasecmp(block->type, LB_DESC_TYPE_SCRIPT)) {
347                                 ErrPrint("Invalid block is used\n");
348                                 return -EINVAL;
349                         }
350
351                         free(block->target_id);
352                         block->target_id = NULL;
353
354                         if (!id || !strlen(id))
355                                 return 0;
356
357                         block->target_id = strdup(id);
358                         if (!block->target_id) {
359                                 ErrPrint("Heap: %s\n", strerror(errno));
360                                 return -ENOMEM;
361                         }
362
363                         return 0;
364                 }
365         }
366
367         return -ENOENT;
368 }
369
370 /*!
371  * \return idx
372  */
373 EAPI int livebox_desc_add_block(struct livebox_desc *handle, const char *id, const char *type, const char *part, const char *data, const char *option)
374 {
375         struct block *block;
376
377         if (!handle || !type)
378                 return -EINVAL;
379
380         if (!part)
381                 part = "";
382
383         if (!data)
384                 data = "";
385
386         block = calloc(1, sizeof(*block));
387         if (!block)
388                 return -ENOMEM;
389
390         block->type = strdup(type);
391         if (!block->type) {
392                 free(block);
393                 return -ENOMEM;
394         }
395
396         block->part = strdup(part);
397         if (!block->part) {
398                 free(block->type);
399                 free(block);
400                 return -ENOMEM;
401         }
402
403         block->data = strdup(data);
404         if (!block->data) {
405                 free(block->type);
406                 free(block->part);
407                 free(block);
408                 return -ENOMEM;
409         }
410
411         if (option) {
412                 block->option = strdup(option);
413                 if (!block->option) {
414                         free(block->data);
415                         free(block->type);
416                         free(block->part);
417                         free(block);
418                         return -ENOMEM;
419                 }
420         }
421
422         if (id) {
423                 block->id = strdup(id);
424                 if (!block->id) {
425                         free(block->option);
426                         free(block->data);
427                         free(block->type);
428                         free(block->part);
429                         free(block);
430                         return -ENOMEM;
431                 }
432         }
433
434         block->idx = handle->last_idx++;
435         handle->block_list = dlist_append(handle->block_list, block);
436         return block->idx;
437 }
438
439 EAPI int livebox_desc_del_block(struct livebox_desc *handle, int idx)
440 {
441         struct dlist *l;
442         struct block *block;
443
444         dlist_foreach(handle->block_list, l, block) {
445                 if (block->idx == idx) {
446                         handle->block_list = dlist_remove(handle->block_list, l);
447                         free(block->type);
448                         free(block->part);
449                         free(block->data);
450                         free(block->option);
451                         free(block->id);
452                         free(block->target_id);
453                         free(block);
454                         return 0;
455                 }
456         }
457
458         return -ENOENT;
459 }
460
461 EAPI struct livebox_buffer *livebox_acquire_buffer(const char *filename, int is_pd, int width, int height, int (*handler)(struct livebox_buffer *, enum buffer_event, double, double, double, void *), void *data)
462 {
463         struct livebox_buffer_data *user_data;
464         const char *pkgname;
465         struct livebox_buffer *handle;
466         char *uri;
467         int uri_len;
468
469         if (!filename || !width || !height) {
470                 ErrPrint("Invalid argument: %p(%dx%d)\n", filename, width, height);
471                 return NULL;
472         }
473
474         user_data = calloc(1, sizeof(*user_data));
475         if (!user_data) {
476                 ErrPrint("Heap: %s\n", strerror(errno));
477                 return NULL;
478         }
479
480         user_data->is_pd = is_pd;
481
482         uri_len = strlen(filename) + strlen(FILE_SCHEMA) + 1;
483         uri = malloc(uri_len);
484         if (!uri) {
485                 ErrPrint("Heap: %s\n", strerror(errno));
486                 free(user_data);
487                 return NULL;
488         }
489
490         snprintf(uri, uri_len, FILE_SCHEMA "%s", filename);
491         pkgname = livebox_find_pkgname(uri);
492         if (!pkgname) {
493                 ErrPrint("Invalid Request\n");
494                 free(user_data);
495                 free(uri);
496                 return NULL;
497         }
498
499         handle = provider_buffer_acquire((!!is_pd) ? TYPE_PD : TYPE_LB, pkgname, uri, width, height, sizeof(int), handler, data);
500         DbgPrint("Acquire buffer for PD(%s), %s, %p\n", pkgname, uri, handle);
501         free(uri);
502
503         (void)provider_buffer_set_user_data(handle, user_data);
504         return handle;
505 }
506
507 EAPI int livebox_request_update(const char *filename)
508 {
509         int uri_len;
510         char *uri;
511         int ret;
512
513         if (!filename) {
514                 ErrPrint("Invalid argument\n");
515                 return -EINVAL;
516         }
517
518         uri_len = strlen(filename) + strlen(FILE_SCHEMA) + 1;
519         uri = malloc(uri_len);
520         if (!uri) {
521                 ErrPrint("Heap: %s\n", strerror(errno));
522                 return -ENOMEM;
523         }
524
525         snprintf(uri, uri_len, FILE_SCHEMA "%s", filename);
526         ret = livebox_request_update_by_id(uri);
527         free(uri);
528         return ret;
529 }
530
531 EAPI unsigned long livebox_pixmap_id(struct livebox_buffer *handle)
532 {
533         return provider_buffer_pixmap_id(handle);
534 }
535
536 EAPI int livebox_release_buffer(struct livebox_buffer *handle)
537 {
538         struct livebox_buffer_data *user_data;
539
540         if (!handle)
541                 return -EINVAL;
542
543         user_data = provider_buffer_user_data(handle);
544         if (user_data) {
545                 free(user_data);
546                 provider_buffer_set_user_data(handle, NULL);
547         }
548
549         DbgPrint("Release buffer\n");
550         return provider_buffer_release(handle);
551 }
552
553 EAPI void *livebox_ref_buffer(struct livebox_buffer *handle)
554 {
555         struct livebox_buffer_data *user_data;
556         void *data;
557         int w, h, size;
558         int ret;
559
560         if (!handle)
561                 return NULL;
562
563         user_data = provider_buffer_user_data(handle);
564         if (!user_data)
565                 return NULL;
566
567         if (user_data->accelerated) {
568                 DbgPrint("H/W accelerated buffer is allocated\n");
569                 return NULL;
570         }
571
572         ret = provider_buffer_get_size(handle, &w, &h, &size);
573
574         data = provider_buffer_ref(handle);
575         if (data && !ret && w > 0 && h > 0 && size > 0) {
576                 memset(data, 0, w * h * size);
577                 provider_buffer_sync(handle);
578         }
579
580         DbgPrint("Ref buffer %ds%d(%d)\n", w, h, size);
581         return data;
582 }
583
584 EAPI int livebox_unref_buffer(void *buffer)
585 {
586         if (!buffer)
587                 return -EINVAL;
588
589         DbgPrint("Unref buffer\n");
590         return provider_buffer_unref(buffer);
591 }
592
593 EAPI int livebox_sync_buffer(struct livebox_buffer *handle)
594 {
595         struct livebox_buffer_data *user_data;
596         const char *pkgname;
597         const char *id;
598
599         if (!handle)
600                 return -EINVAL;
601
602         user_data = provider_buffer_user_data(handle);
603         if (!user_data) {
604                 ErrPrint("Invalid buffer\n");
605                 return -EINVAL;
606         }
607
608         if (user_data->accelerated) {
609                 DbgPrint("H/W Buffer allocated. skip the sync buffer\n");
610                 return 0;
611         }
612
613         pkgname = provider_buffer_pkgname(handle);
614         if (!pkgname) {
615                 ErrPrint("Invalid buffer handler\n");
616                 return -EINVAL;
617         }
618
619         id = provider_buffer_id(handle);
620         if (!id) {
621                 ErrPrint("Invalid buffer handler\n");
622                 return -EINVAL;
623         }
624
625         DbgPrint("Sync buffer\n");
626         provider_buffer_sync(handle);
627
628         if (user_data->is_pd) {
629                 if (provider_send_desc_updated(pkgname, id, NULL) < 0)
630                         ErrPrint("Failed to send PD updated (%s)\n", id);
631         } else {
632                 int w;
633                 int h;
634                 int pixel_size;
635
636                 if (provider_buffer_get_size(handle, &w, &h, &pixel_size) < 0)
637                         ErrPrint("Failed to get size (%s)\n", id);
638
639                 if (provider_send_updated(pkgname, id, w, h, -1.0f, NULL, NULL) < 0)
640                         ErrPrint("Failed to send updated (%s)\n", id);
641         }
642         return 0;
643 }
644
645 EAPI int livebox_support_hw_buffer(struct livebox_buffer *handle)
646 {
647         if (!handle)
648                 return -EINVAL;
649
650         return provider_buffer_pixmap_is_support_hw(handle);
651 }
652
653 EAPI int livebox_create_hw_buffer(struct livebox_buffer *handle)
654 {
655         struct livebox_buffer_data *user_data;
656         int ret;
657
658         if (!handle)
659                 return -EINVAL;
660
661         user_data = provider_buffer_user_data(handle);
662         if (!user_data)
663                 return -EINVAL;
664
665         if (user_data->accelerated)
666                 return -EALREADY;
667
668         ret = provider_buffer_pixmap_create_hw(handle);
669         user_data->accelerated = (ret == 0);
670         return ret;
671 }
672
673 EAPI int livebox_destroy_hw_buffer(struct livebox_buffer *handle)
674 {
675         struct livebox_buffer_data *user_data;
676         if (!handle)
677                 return -EINVAL;
678
679         user_data = provider_buffer_user_data(handle);
680         if (!user_data || !user_data->accelerated)
681                 return -EINVAL;
682
683         user_data->accelerated = 0;
684
685         return provider_buffer_pixmap_destroy_hw(handle);
686 }
687
688 EAPI void *livebox_buffer_hw_buffer(struct livebox_buffer *handle)
689 {
690         struct livebox_buffer_data *user_data;
691
692         if (!handle)
693                 return NULL;
694
695         user_data = provider_buffer_user_data(handle);
696         if (!user_data || !user_data->accelerated)
697                 return -EINVAL;
698
699         return provider_buffer_pixmap_hw_addr(handle);
700 }
701
702 EAPI int livebox_buffer_pre_render(struct livebox_buffer *handle)
703 {
704         struct livebox_buffer_data *user_data;
705
706         if (!handle)
707                 return -EINVAL;
708
709         user_data = provider_buffer_user_data(handle);
710         if (!user_data)
711                 return -EINVAL;
712
713         if (!user_data->accelerated)
714                 return 0;
715
716         /*!
717          * \note
718          * Do preprocessing for accessing the H/W render buffer
719          */
720         return provider_buffer_pre_render(handle);
721 }
722
723 EAPI int livebox_buffer_post_render(struct livebox_buffer *handle)
724 {
725         int ret;
726         const char *pkgname;
727         const char *id;
728         struct livebox_buffer_data *user_data;
729
730         if (!handle)
731                 return -EINVAL;
732
733         user_data = provider_buffer_user_data(handle);
734         if (!user_data)
735                 return -EINVAL;
736
737         if (!user_data->accelerated)
738                 return 0;
739
740         pkgname = provider_buffer_pkgname(handle);
741         if (!pkgname) {
742                 ErrPrint("Invalid buffer handle\n");
743                 return -EINVAL;
744         }
745
746         id = provider_buffer_id(handle);
747         if (!id) {
748                 ErrPrint("Invalid buffer handler\n");
749                 return -EINVAL;
750         }
751
752         ret = provider_buffer_post_render(handle);
753         if (ret < 0) {
754                 ErrPrint("Failed to post render processing\n");
755                 return ret;
756         }
757
758         if (user_data->is_pd == 1) {
759                 if (provider_send_desc_updated(pkgname, id, NULL) < 0)
760                         ErrPrint("Failed to send PD updated (%s)\n", id);
761         } else {
762                 int w;
763                 int h;
764                 int pixel_size;
765
766                 if (provider_buffer_get_size(handle, &w, &h, &pixel_size) < 0)
767                         ErrPrint("Failed to get size (%s)\n", id);
768
769                 if (provider_send_updated(pkgname, id, w, h, -1.0f, NULL, NULL) < 0)
770                         ErrPrint("Failed to send updated (%s)\n", id);
771         }
772
773         return 0;
774 }
775
776 /* End of a file */