Update spec
[platform/framework/web/livebox-viewer.git] / src / fb_wayland.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.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 <sys/mman.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <stddef.h>
27 #include <sys/shm.h>
28 #include <sys/ipc.h>
29
30 #include <dlog.h>
31 #include <livebox-errno.h> /* For error code */
32
33 #include "debug.h"
34 #include "util.h"
35 #include "fb.h"
36
37 int errno;
38
39 struct fb_info {
40         char *id;
41         int w;
42         int h;
43         int bufsz;
44         void *buffer;
45
46         int pixels;
47         int handle;
48 };
49
50 struct buffer { /*!< Must has to be sync with slave & provider */
51         enum {
52                 CREATED = 0x00beef00,
53                 DESTROYED = 0x00dead00
54         } state;
55         enum buffer_type type;
56         int refcnt;
57         void *info;
58         char data[];
59 };
60
61 static struct {
62 } s_info = {
63 };
64
65 int fb_init(void *disp)
66 {
67         return 0;
68 }
69
70 int fb_fini(void)
71 {
72         return 0;
73 }
74
75 static inline void update_fb_size(struct fb_info *info)
76 {
77         info->bufsz = info->w * info->h * info->pixels;
78 }
79
80 static inline int sync_for_file(struct fb_info *info)
81 {
82         int fd;
83         struct buffer *buffer;
84
85         buffer = info->buffer;
86
87         if (!buffer) { /* Ignore this sync request */
88                 return LB_STATUS_SUCCESS;
89         }
90
91         if (buffer->state != CREATED) {
92                 ErrPrint("Invalid state of a FB\n");
93                 return LB_STATUS_ERROR_INVALID;
94         }
95
96         if (buffer->type != BUFFER_TYPE_FILE) {
97                 ErrPrint("Invalid buffer\n");
98                 return LB_STATUS_SUCCESS;
99         }
100
101         fd = open(util_uri_to_path(info->id), O_RDONLY);
102         if (fd < 0) {
103                 ErrPrint("Failed to open a file (%s) because of (%s)\n",
104                                         util_uri_to_path(info->id), strerror(errno));
105
106                 /*!
107                  * \note
108                  * But return ZERO, even if we couldn't get a buffer file,
109                  * the viewer can draw empty screen.
110                  *
111                  * and then update it after it gots update events
112                  */
113                 return LB_STATUS_SUCCESS;
114         }
115
116         if (read(fd, buffer->data, info->bufsz) != info->bufsz) {
117                 ErrPrint("read: %s\n", strerror(errno));
118                 if (close(fd) < 0) {
119                         ErrPrint("close: %s\n", strerror(errno));
120                 }
121
122                 /*!
123                  * \note
124                  * But return ZERO, even if we couldn't get a buffer file,
125                  * the viewer can draw empty screen.
126                  *
127                  * and then update it after it gots update events
128                  */
129                 return LB_STATUS_SUCCESS;
130         }
131
132         if (close(fd) < 0) {
133                 ErrPrint("close: %s\n", strerror(errno));
134         }
135         return LB_STATUS_SUCCESS;
136 }
137
138 int fb_sync(struct fb_info *info)
139 {
140         if (!info) {
141                 ErrPrint("FB Handle is not valid\n");
142                 return LB_STATUS_ERROR_INVALID;
143         }
144
145         if (!info->id || info->id[0] == '\0') {
146                 DbgPrint("Ingore sync\n");
147                 return LB_STATUS_SUCCESS;
148         }
149
150         if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
151                 return sync_for_file(info);
152         } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
153         } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
154                 /* No need to do sync */ 
155                 return LB_STATUS_SUCCESS;
156         }
157
158         return LB_STATUS_ERROR_INVALID;
159 }
160
161 struct fb_info *fb_create(const char *id, int w, int h)
162 {
163         struct fb_info *info;
164
165         if (!id || id[0] == '\0') {
166                 ErrPrint("Invalid ID\n");
167                 return NULL;
168         }
169
170         info = calloc(1, sizeof(*info));
171         if (!info) {
172                 ErrPrint("Heap: %s\n", strerror(errno));
173                 return NULL;
174         }
175
176         info->id = strdup(id);
177         if (!info->id) {
178                 ErrPrint("Heap: %s\n", strerror(errno));
179                 free(info);
180                 return NULL;
181         }
182
183         info->pixels = sizeof(int);     /* Use the default pixels(depth) */
184
185         if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
186                 DbgPrint("SHMID: %d is gotten\n", info->handle);
187         } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) {
188                 DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels);
189                 ErrPrint("Unsupported\n");
190                 free(info);
191                 return NULL;
192         } else {
193                 info->handle = LB_STATUS_ERROR_INVALID;
194         }
195
196         info->bufsz = 0;
197         info->buffer = NULL;
198         info->w = w;
199         info->h = h;
200
201         return info;
202 }
203
204 int fb_destroy(struct fb_info *info)
205 {
206         if (!info) {
207                 ErrPrint("Handle is not valid\n");
208                 return LB_STATUS_ERROR_INVALID;
209         }
210
211         if (info->buffer) {
212                 struct buffer *buffer;
213                 buffer = info->buffer;
214
215                 buffer->info = NULL;
216         }
217
218         free(info->id);
219         free(info);
220         return LB_STATUS_SUCCESS;
221 }
222
223 int fb_is_created(struct fb_info *info)
224 {
225         if (!info) {
226                 ErrPrint("Handle is not valid\n");
227                 return 0;
228         }
229
230         if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) {
231                 return 1;
232         } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) {
233                 return 1;
234         } else {
235                 const char *path;
236                 path = util_uri_to_path(info->id);
237                 if (path && access(path, F_OK | R_OK) == 0) {
238                         return 1;
239                 } else {
240                         ErrPrint("access: %s (%s)\n", strerror(errno), path);
241                 }
242         }
243
244         return 0;
245 }
246
247 void *fb_acquire_buffer(struct fb_info *info)
248 {
249         struct buffer *buffer;
250
251         if (!info) {
252                 ErrPrint("info == NIL\n");
253                 return NULL;
254         }
255
256         if (!info->buffer) {
257                 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
258                         ErrPrint("Unsupported Type\n");
259                         return NULL;
260                 } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
261                         update_fb_size(info);
262
263                         buffer = calloc(1, sizeof(*buffer) + info->bufsz);
264                         if (!buffer) {
265                                 ErrPrint("Heap: %s\n", strerror(errno));
266                                 info->bufsz = 0;
267                                 return NULL;
268                         }
269
270                         buffer->type = BUFFER_TYPE_FILE;
271                         buffer->refcnt = 0;
272                         buffer->state = CREATED;
273                         buffer->info = info;
274                         info->buffer = buffer;
275
276                         sync_for_file(info);
277                 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
278                         buffer = shmat(info->handle, NULL, 0);
279                         if (buffer == (void *)-1) {
280                                 ErrPrint("shmat: %s (%d)\n", strerror(errno), info->handle);
281                                 return NULL;
282                         }
283
284                         return buffer->data;
285                 } else {
286                         ErrPrint("Buffer is not created (%s)\n", info->id);
287                         return NULL;
288                 }
289         }
290
291         buffer = info->buffer;
292
293         switch (buffer->type) {
294         case BUFFER_TYPE_FILE:
295                 buffer->refcnt++;
296                 break;
297         case BUFFER_TYPE_PIXMAP:
298         default:
299                 DbgPrint("Unknwon FP: %d\n", buffer->type);
300                 break;
301         }
302
303         return buffer->data;
304 }
305
306 int fb_release_buffer(void *data)
307 {
308         struct buffer *buffer;
309
310         if (!data) {
311                 ErrPrint("buffer data == NIL\n");
312                 return LB_STATUS_ERROR_INVALID;
313         }
314
315         buffer = container_of(data, struct buffer, data);
316
317         if (buffer->state != CREATED) {
318                 ErrPrint("Invalid handle\n");
319                 return LB_STATUS_ERROR_INVALID;
320         }
321
322         switch (buffer->type) {
323         case BUFFER_TYPE_SHM:
324                 if (shmdt(buffer) < 0) {
325                         ErrPrint("shmdt: %s\n", strerror(errno));
326                 }
327                 break;
328         case BUFFER_TYPE_FILE:
329                 buffer->refcnt--;
330                 if (buffer->refcnt == 0) {
331                         struct fb_info *info;
332                         info = buffer->info;
333
334                         buffer->state = DESTROYED;
335                         free(buffer);
336
337                         if (info && info->buffer == buffer) {
338                                 info->buffer = NULL;
339                         }
340                 }
341                 break;
342         case BUFFER_TYPE_PIXMAP:
343         default:
344                 ErrPrint("Unknwon buffer type\n");
345                 break;
346         }
347
348         return LB_STATUS_SUCCESS;
349 }
350
351 int fb_refcnt(void *data)
352 {
353         struct buffer *buffer;
354         struct shmid_ds buf;
355         int ret;
356
357         if (!data) {
358                 return LB_STATUS_ERROR_INVALID;
359         }
360
361         buffer = container_of(data, struct buffer, data);
362
363         if (buffer->state != CREATED) {
364                 ErrPrint("Invalid handle\n");
365                 return LB_STATUS_ERROR_INVALID;
366         }
367
368         switch (buffer->type) {
369         case BUFFER_TYPE_SHM:
370                 if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) {
371                         ErrPrint("Error: %s\n", strerror(errno));
372                         return LB_STATUS_ERROR_FAULT;
373                 }
374
375                 ret = buf.shm_nattch;
376                 break;
377         case BUFFER_TYPE_FILE:
378                 ret = buffer->refcnt;
379                 break;
380         case BUFFER_TYPE_PIXMAP:
381         default:
382                 ret = LB_STATUS_ERROR_INVALID;
383                 break;
384         }
385
386         return ret;
387 }
388
389 const char *fb_id(struct fb_info *info)
390 {
391         return info ? info->id : NULL;
392 }
393
394 int fb_get_size(struct fb_info *info, int *w, int *h)
395 {
396         if (!info) {
397                 ErrPrint("Handle is not valid\n");
398                 return LB_STATUS_ERROR_INVALID;
399         }
400
401         *w = info->w;
402         *h = info->h;
403         return LB_STATUS_SUCCESS;
404 }
405
406 int fb_size(struct fb_info *info)
407 {
408         if (!info) {
409                 return 0;
410         }
411
412         update_fb_size(info);
413
414         return info->bufsz;
415 }
416
417 int fb_type(struct fb_info *info)
418 {
419         struct buffer *buffer;
420
421         if (!info) {
422                 return BUFFER_TYPE_ERROR;
423         }
424
425         buffer = info->buffer;
426         if (!buffer) {
427                 int type = BUFFER_TYPE_ERROR;
428                 /*!
429                  * \note
430                  * Try to get this from SCHEMA
431                  */
432                 if (info->id) {
433                         if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
434                                 type = BUFFER_TYPE_FILE;
435                         } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
436                                 /* Unsupported type */
437                         } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
438                                 type = BUFFER_TYPE_SHM;
439                         }
440                 }
441
442                 return type;
443         }
444
445         return buffer->type;
446 }
447 /* End of a file */