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 void update_fb_size(struct fb_info *info)
111 info->bufsz = info->w * info->h * s_info.depth;
114 static inline int sync_for_file(struct fb_info *info)
117 struct buffer *buffer;
119 buffer = info->buffer;
121 if (!buffer) { /* Ignore this sync request */
122 return LB_STATUS_SUCCESS;
125 if (buffer->state != CREATED) {
126 ErrPrint("Invalid state of a FB\n");
127 return LB_STATUS_ERROR_INVALID;
130 if (buffer->type != BUFFER_TYPE_FILE) {
131 ErrPrint("Invalid buffer\n");
132 return LB_STATUS_SUCCESS;
135 fd = open(util_uri_to_path(info->id), O_RDONLY);
137 ErrPrint("Failed to open a file (%s) because of (%s)\n",
138 util_uri_to_path(info->id), strerror(errno));
142 * But return ZERO, even if we couldn't get a buffer file,
143 * the viewer can draw empty screen.
145 * and then update it after it gots update events
147 return LB_STATUS_SUCCESS;
150 if (read(fd, buffer->data, info->bufsz) != info->bufsz) {
151 ErrPrint("read: %s\n", strerror(errno));
153 ErrPrint("close: %s\n", strerror(errno));
158 * But return ZERO, even if we couldn't get a buffer file,
159 * the viewer can draw empty screen.
161 * and then update it after it gots update events
163 return LB_STATUS_SUCCESS;
167 ErrPrint("close: %s\n", strerror(errno));
169 return LB_STATUS_SUCCESS;
172 static inline __attribute__((always_inline)) int sync_for_pixmap(struct fb_info *info)
174 struct buffer *buffer;
178 buffer = info->buffer;
179 if (!buffer) { /*!< Ignore this sync request */
180 return LB_STATUS_SUCCESS;
183 if (buffer->state != CREATED) {
184 ErrPrint("Invalid state of a FB\n");
185 return LB_STATUS_ERROR_INVALID;
188 if (buffer->type != BUFFER_TYPE_PIXMAP) {
189 ErrPrint("Invalid buffer\n");
190 return LB_STATUS_SUCCESS;
194 s_info.disp = XOpenDisplay(NULL);
198 s_info.disp_is_opened = 1;
200 screen = DefaultScreenOfDisplay(s_info.disp);
202 s_info.screen = DefaultScreen(s_info.disp);
203 s_info.visual = DefaultVisualOfScreen(screen);
205 ErrPrint("Failed to open a display\n");
206 return LB_STATUS_ERROR_FAULT;
210 if (info->handle == 0) {
211 ErrPrint("Pixmap ID is not valid\n");
212 return LB_STATUS_ERROR_INVALID;
215 if (info->bufsz == 0) {
217 * If the client does not acquire the buffer,
218 * This function will do nothing.
219 * It will work only if the buffer is acquired.
220 * To sync its contents.
222 DbgPrint("Nothing can be sync\n");
223 return LB_STATUS_SUCCESS;
226 si.shmid = shmget(IPC_PRIVATE, info->bufsz, IPC_CREAT | 0666);
228 ErrPrint("shmget: %s\n", strerror(errno));
229 return LB_STATUS_ERROR_FAULT;
233 si.shmaddr = shmat(si.shmid, NULL, 0);
234 if (si.shmaddr == (void *)-1) {
235 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
236 ErrPrint("shmctl: %s\n", strerror(errno));
239 return LB_STATUS_ERROR_FAULT;
244 * Use the 24 bits Pixmap for Video player
246 xim = XShmCreateImage(s_info.disp, s_info.visual,
247 (s_info.depth << 3), ZPixmap, NULL,
251 if (shmdt(si.shmaddr) < 0) {
252 ErrPrint("shmdt: %s\n", strerror(errno));
255 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
256 ErrPrint("shmctl: %s\n", strerror(errno));
259 return LB_STATUS_ERROR_FAULT;
262 xim->data = si.shmaddr;
263 XShmAttach(s_info.disp, &si);
265 XShmGetImage(s_info.disp, info->handle, xim, 0, 0, 0xFFFFFFFF);
266 XSync(s_info.disp, False);
268 memcpy(buffer->data, xim->data, info->bufsz);
270 XShmDetach(s_info.disp, &si);
273 if (shmdt(si.shmaddr) < 0) {
274 ErrPrint("shmdt: %s\n", strerror(errno));
277 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
278 ErrPrint("shmctl: %s\n", strerror(errno));
281 return LB_STATUS_SUCCESS;
284 int fb_sync(struct fb_info *info)
287 ErrPrint("FB Handle is not valid\n");
288 return LB_STATUS_ERROR_INVALID;
291 if (!info->id || info->id[0] == '\0') {
292 DbgPrint("Ingore sync\n");
293 return LB_STATUS_SUCCESS;
296 if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
297 return sync_for_file(info);
298 } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
299 return sync_for_pixmap(info);
300 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
301 /* No need to do sync */
302 return LB_STATUS_SUCCESS;
305 return LB_STATUS_ERROR_INVALID;
308 struct fb_info *fb_create(const char *id, int w, int h)
310 struct fb_info *info;
312 if (!id || id[0] == '\0') {
313 ErrPrint("Invalid ID\n");
317 info = calloc(1, sizeof(*info));
319 CRITICAL_LOG("Heap: %s\n", strerror(errno));
323 info->id = strdup(id);
325 CRITICAL_LOG("Heap: %s\n", strerror(errno));
330 if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
331 DbgPrint("SHMID: %d is gotten\n", info->handle);
332 } else if (sscanf(info->id, SCHEMA_PIXMAP "%d", &info->handle) == 1) {
333 DbgPrint("PIXMAP-SHMID: %d is gotten\n", info->handle);
335 info->handle = LB_STATUS_ERROR_INVALID;
346 int fb_destroy(struct fb_info *info)
349 ErrPrint("Handle is not valid\n");
350 return LB_STATUS_ERROR_INVALID;
354 struct buffer *buffer;
355 buffer = info->buffer;
362 return LB_STATUS_SUCCESS;
365 int fb_is_created(struct fb_info *info)
368 ErrPrint("Handle is not valid\n");
372 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) {
374 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) {
378 path = util_uri_to_path(info->id);
379 if (path && access(path, F_OK | R_OK) == 0) {
382 ErrPrint("access: %s (%s)\n", strerror(errno), path);
389 void *fb_acquire_buffer(struct fb_info *info)
391 struct buffer *buffer;
394 ErrPrint("info == NIL\n");
399 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
400 update_fb_size(info);
402 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
404 CRITICAL_LOG("Heap: %s\n", strerror(errno));
409 buffer->type = BUFFER_TYPE_PIXMAP;
411 buffer->state = CREATED;
413 info->buffer = buffer;
417 * Just update from here.
419 sync_for_pixmap(info);
420 } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
421 update_fb_size(info);
423 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
425 CRITICAL_LOG("Heap: %s\n", strerror(errno));
430 buffer->type = BUFFER_TYPE_FILE;
432 buffer->state = CREATED;
434 info->buffer = buffer;
437 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
438 buffer = shmat(info->handle, NULL, 0);
439 if (buffer == (void *)-1) {
440 ErrPrint("shmat: %s\n", strerror(errno));
446 ErrPrint("Buffer is not created (%s)\n", info->id);
451 buffer = info->buffer;
453 switch (buffer->type) {
454 case BUFFER_TYPE_PIXMAP:
457 case BUFFER_TYPE_FILE:
461 DbgPrint("Unknwon FP: %d\n", buffer->type);
468 int fb_release_buffer(void *data)
470 struct buffer *buffer;
473 ErrPrint("buffer data == NIL\n");
474 return LB_STATUS_ERROR_INVALID;
477 buffer = container_of(data, struct buffer, data);
479 if (buffer->state != CREATED) {
480 ErrPrint("Invalid handle\n");
481 return LB_STATUS_ERROR_INVALID;
484 switch (buffer->type) {
485 case BUFFER_TYPE_SHM:
486 if (shmdt(buffer) < 0) {
487 ErrPrint("shmdt: %s\n", strerror(errno));
490 case BUFFER_TYPE_PIXMAP:
492 if (buffer->refcnt == 0) {
493 struct fb_info *info;
496 buffer->state = DESTROYED;
499 if (info && info->buffer == buffer) {
504 case BUFFER_TYPE_FILE:
506 if (buffer->refcnt == 0) {
507 struct fb_info *info;
510 buffer->state = DESTROYED;
513 if (info && info->buffer == buffer) {
519 ErrPrint("Unknwon buffer type\n");
523 return LB_STATUS_SUCCESS;
526 int fb_refcnt(void *data)
528 struct buffer *buffer;
533 return LB_STATUS_ERROR_INVALID;
536 buffer = container_of(data, struct buffer, data);
538 if (buffer->state != CREATED) {
539 ErrPrint("Invalid handle\n");
540 return LB_STATUS_ERROR_INVALID;
543 switch (buffer->type) {
544 case BUFFER_TYPE_SHM:
545 if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) {
546 ErrPrint("Error: %s\n", strerror(errno));
547 return LB_STATUS_ERROR_FAULT;
550 ret = buf.shm_nattch;
552 case BUFFER_TYPE_PIXMAP:
553 ret = buffer->refcnt;
555 case BUFFER_TYPE_FILE:
556 ret = buffer->refcnt;
559 ret = LB_STATUS_ERROR_INVALID;
566 const char *fb_id(struct fb_info *info)
568 return info ? info->id : NULL;
571 int fb_get_size(struct fb_info *info, int *w, int *h)
574 ErrPrint("Handle is not valid\n");
575 return LB_STATUS_ERROR_INVALID;
580 return LB_STATUS_SUCCESS;
583 int fb_size(struct fb_info *info)
589 update_fb_size(info);