2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
24 #include <sys/types.h>
31 #include <X11/extensions/XShm.h>
32 #include <X11/Xutil.h>
35 #include <livebox-errno.h> /* For error code */
40 #include "critical_log.h"
54 struct buffer { /*!< Must has to be sync with slave & provider */
57 DESTROYED = 0x00dead00
59 enum buffer_type type;
79 int fb_init(void *disp)
85 screen = DefaultScreenOfDisplay(s_info.disp);
87 s_info.screen = DefaultScreen(s_info.disp);
88 s_info.visual = DefaultVisualOfScreen(screen);
91 s_info.depth = sizeof(int); //DefaultDepthOfScreen(screen);
97 if (s_info.disp_is_opened && s_info.disp) {
98 XCloseDisplay(s_info.disp);
102 s_info.disp_is_opened = 0;
103 s_info.visual = NULL;
109 static inline int sync_for_file(struct fb_info *info)
112 struct buffer *buffer;
114 buffer = info->buffer;
116 if (!buffer) { /* Ignore this sync request */
117 return LB_STATUS_SUCCESS;
120 if (buffer->state != CREATED) {
121 ErrPrint("Invalid state of a FB\n");
122 return LB_STATUS_ERROR_INVALID;
125 if (buffer->type != BUFFER_TYPE_FILE) {
126 ErrPrint("Invalid buffer\n");
127 return LB_STATUS_SUCCESS;
130 fd = open(util_uri_to_path(info->id), O_RDONLY);
132 ErrPrint("Failed to open a file (%s) because of (%s)\n",
133 util_uri_to_path(info->id), strerror(errno));
137 * But return ZERO, even if we couldn't get a buffer file,
138 * the viewer can draw empty screen.
140 * and then update it after it gots update events
142 return LB_STATUS_SUCCESS;
145 if (read(fd, buffer->data, info->bufsz) != info->bufsz) {
146 ErrPrint("read: %s\n", strerror(errno));
148 ErrPrint("close: %s\n", strerror(errno));
153 * But return ZERO, even if we couldn't get a buffer file,
154 * the viewer can draw empty screen.
156 * and then update it after it gots update events
158 return LB_STATUS_SUCCESS;
162 ErrPrint("close: %s\n", strerror(errno));
164 return LB_STATUS_SUCCESS;
167 static inline __attribute__((always_inline)) int sync_for_pixmap(struct fb_info *info)
169 struct buffer *buffer;
173 buffer = info->buffer;
174 if (!buffer) { /*!< Ignore this sync request */
175 return LB_STATUS_SUCCESS;
178 if (buffer->state != CREATED) {
179 ErrPrint("Invalid state of a FB\n");
180 return LB_STATUS_ERROR_INVALID;
183 if (buffer->type != BUFFER_TYPE_PIXMAP) {
184 ErrPrint("Invalid buffer\n");
185 return LB_STATUS_SUCCESS;
189 s_info.disp = XOpenDisplay(NULL);
193 s_info.disp_is_opened = 1;
195 screen = DefaultScreenOfDisplay(s_info.disp);
197 s_info.screen = DefaultScreen(s_info.disp);
198 s_info.visual = DefaultVisualOfScreen(screen);
200 ErrPrint("Failed to open a display\n");
201 return LB_STATUS_ERROR_FAULT;
205 if (info->handle == 0) {
206 ErrPrint("Pixmap ID is not valid\n");
207 return LB_STATUS_ERROR_INVALID;
210 if (info->bufsz == 0) {
211 DbgPrint("Nothing can be sync\n");
212 return LB_STATUS_SUCCESS;
215 si.shmid = shmget(IPC_PRIVATE, info->bufsz, IPC_CREAT | 0666);
217 ErrPrint("shmget: %s\n", strerror(errno));
218 return LB_STATUS_ERROR_FAULT;
222 si.shmaddr = shmat(si.shmid, NULL, 0);
223 if (si.shmaddr == (void *)-1) {
224 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
225 ErrPrint("shmctl: %s\n", strerror(errno));
228 return LB_STATUS_ERROR_FAULT;
233 * Use the 24 bits Pixmap for Video player
235 xim = XShmCreateImage(s_info.disp, s_info.visual,
236 (s_info.depth << 3), ZPixmap, NULL,
240 if (shmdt(si.shmaddr) < 0) {
241 ErrPrint("shmdt: %s\n", strerror(errno));
244 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
245 ErrPrint("shmctl: %s\n", strerror(errno));
248 return LB_STATUS_ERROR_FAULT;
251 xim->data = si.shmaddr;
252 XShmAttach(s_info.disp, &si);
254 XShmGetImage(s_info.disp, info->handle, xim, 0, 0, 0xFFFFFFFF);
255 XSync(s_info.disp, False);
257 memcpy(buffer->data, xim->data, info->bufsz);
259 XShmDetach(s_info.disp, &si);
262 if (shmdt(si.shmaddr) < 0) {
263 ErrPrint("shmdt: %s\n", strerror(errno));
266 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
267 ErrPrint("shmctl: %s\n", strerror(errno));
270 return LB_STATUS_SUCCESS;
273 int fb_sync(struct fb_info *info)
276 ErrPrint("FB Handle is not valid\n");
277 return LB_STATUS_ERROR_INVALID;
280 if (!info->id || info->id[0] == '\0') {
281 DbgPrint("Ingore sync\n");
282 return LB_STATUS_SUCCESS;
285 if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
286 return sync_for_file(info);
287 } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
288 return sync_for_pixmap(info);
289 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
290 /* No need to do sync */
291 return LB_STATUS_SUCCESS;
294 return LB_STATUS_ERROR_INVALID;
297 struct fb_info *fb_create(const char *id, int w, int h)
299 struct fb_info *info;
301 if (!id || id[0] == '\0') {
302 ErrPrint("Invalid ID\n");
306 info = calloc(1, sizeof(*info));
308 CRITICAL_LOG("Heap: %s\n", strerror(errno));
312 info->id = strdup(id);
314 CRITICAL_LOG("Heap: %s\n", strerror(errno));
319 if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
320 DbgPrint("SHMID: %d is gotten\n", info->handle);
321 } else if (sscanf(info->id, SCHEMA_PIXMAP "%d", &info->handle) == 1) {
322 DbgPrint("PIXMAP-SHMID: %d is gotten\n", info->handle);
324 info->handle = LB_STATUS_ERROR_INVALID;
335 int fb_destroy(struct fb_info *info)
338 ErrPrint("Handle is not valid\n");
339 return LB_STATUS_ERROR_INVALID;
343 struct buffer *buffer;
344 buffer = info->buffer;
351 return LB_STATUS_SUCCESS;
354 int fb_is_created(struct fb_info *info)
357 ErrPrint("Handle is not valid\n");
361 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) {
363 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) {
367 path = util_uri_to_path(info->id);
368 if (path && access(path, F_OK | R_OK) == 0) {
371 ErrPrint("access: %s (%s)\n", strerror(errno), path);
378 void *fb_acquire_buffer(struct fb_info *info)
380 struct buffer *buffer;
383 ErrPrint("info == NIL\n");
388 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
389 info->bufsz = info->w * info->h * s_info.depth;
390 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
392 CRITICAL_LOG("Heap: %s\n", strerror(errno));
397 buffer->type = BUFFER_TYPE_PIXMAP;
399 buffer->state = CREATED;
401 info->buffer = buffer;
405 * Just update from here.
407 sync_for_pixmap(info);
408 } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
409 info->bufsz = info->w * info->h * s_info.depth;
410 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
412 CRITICAL_LOG("Heap: %s\n", strerror(errno));
417 buffer->type = BUFFER_TYPE_FILE;
419 buffer->state = CREATED;
421 info->buffer = buffer;
424 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
425 buffer = shmat(info->handle, NULL, 0);
426 if (buffer == (void *)-1) {
427 ErrPrint("shmat: %s\n", strerror(errno));
433 ErrPrint("Buffer is not created (%s)\n", info->id);
438 buffer = info->buffer;
440 switch (buffer->type) {
441 case BUFFER_TYPE_PIXMAP:
444 case BUFFER_TYPE_FILE:
448 DbgPrint("Unknwon FP: %d\n", buffer->type);
455 int fb_release_buffer(void *data)
457 struct buffer *buffer;
460 ErrPrint("buffer data == NIL\n");
461 return LB_STATUS_ERROR_INVALID;
464 buffer = container_of(data, struct buffer, data);
466 if (buffer->state != CREATED) {
467 ErrPrint("Invalid handle\n");
468 return LB_STATUS_ERROR_INVALID;
471 switch (buffer->type) {
472 case BUFFER_TYPE_SHM:
473 if (shmdt(buffer) < 0) {
474 ErrPrint("shmdt: %s\n", strerror(errno));
477 case BUFFER_TYPE_PIXMAP:
479 if (buffer->refcnt == 0) {
480 struct fb_info *info;
483 buffer->state = DESTROYED;
486 if (info && info->buffer == buffer) {
491 case BUFFER_TYPE_FILE:
493 if (buffer->refcnt == 0) {
494 struct fb_info *info;
497 buffer->state = DESTROYED;
500 if (info && info->buffer == buffer) {
506 ErrPrint("Unknwon buffer type\n");
510 return LB_STATUS_SUCCESS;
513 int fb_refcnt(void *data)
515 struct buffer *buffer;
520 return LB_STATUS_ERROR_INVALID;
523 buffer = container_of(data, struct buffer, data);
525 if (buffer->state != CREATED) {
526 ErrPrint("Invalid handle\n");
527 return LB_STATUS_ERROR_INVALID;
530 switch (buffer->type) {
531 case BUFFER_TYPE_SHM:
532 if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) {
533 ErrPrint("Error: %s\n", strerror(errno));
534 return LB_STATUS_ERROR_FAULT;
537 ret = buf.shm_nattch;
539 case BUFFER_TYPE_PIXMAP:
540 ret = buffer->refcnt;
542 case BUFFER_TYPE_FILE:
543 ret = buffer->refcnt;
546 ret = LB_STATUS_ERROR_INVALID;
553 const char *fb_id(struct fb_info *info)
555 return info ? info->id : NULL;
558 int fb_get_size(struct fb_info *info, int *w, int *h)
561 ErrPrint("Handle is not valid\n");
562 return LB_STATUS_ERROR_INVALID;
567 return LB_STATUS_SUCCESS;
570 int fb_size(struct fb_info *info)
576 info->bufsz = info->w * info->h * s_info.depth;