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 <dynamicbox_errno.h> /* For error code */
36 #include <dynamicbox_service.h> /* For buffer event data */
37 #include <dynamicbox_buffer.h>
57 int fb_init(void *disp)
63 screen = DefaultScreenOfDisplay(s_info.disp);
65 s_info.screen = DefaultScreen(s_info.disp);
66 s_info.visual = DefaultVisualOfScreen(screen);
69 return DBOX_STATUS_ERROR_NONE;
74 if (s_info.disp_is_opened && s_info.disp) {
75 XCloseDisplay(s_info.disp);
79 s_info.disp_is_opened = 0;
85 static inline void update_fb_size(struct fb_info *info)
87 info->bufsz = info->w * info->h * info->pixels;
90 static int sync_for_file(struct fb_info *info, int x, int y, int w, int h)
93 dynamicbox_fb_t buffer;
95 buffer = info->buffer;
97 if (!buffer) { /* Ignore this sync request */
98 return DBOX_STATUS_ERROR_NONE;
101 if (buffer->state != DBOX_FB_STATE_CREATED) {
102 ErrPrint("Invalid state of a FB\n");
103 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
106 if (buffer->type != DBOX_FB_TYPE_FILE) {
107 ErrPrint("Invalid buffer\n");
108 return DBOX_STATUS_ERROR_NONE;
111 fd = open(util_uri_to_path(info->id), O_RDONLY);
113 ErrPrint("Failed to open a file (%s) because of (%s)\n",
114 util_uri_to_path(info->id), strerror(errno));
118 * But return ZERO, even if we couldn't get a buffer file,
119 * the viewer can draw empty screen.
121 * and then update it after it gots update events
123 return DBOX_STATUS_ERROR_NONE;
128 * Could we get some advantage if we load a part of file instead of loading all of them?
130 if (x != 0 || y != 0 || info->w != w || info->h != h) {
135 for (iy = y; iy < h; iy++) {
136 index = iy * info->w + x;
137 width = w * info->pixels;
139 if (lseek(fd, index * info->pixels, SEEK_SET) != index * info->pixels) {
140 ErrPrint("lseek: %s\n", strerror(errno));
142 ErrPrint("close: %s\n", strerror(errno));
146 * But return ZERO, even if we couldn't get a buffer file,
147 * the viewer can draw empty screen.
149 * and then update it after it gots update events
151 return DBOX_STATUS_ERROR_NONE;
154 if (read(fd, ((unsigned int *)buffer->data) + index, width) != width) {
156 ErrPrint("close: %s\n", strerror(errno));
160 * But return ZERO, even if we couldn't get a buffer file,
161 * the viewer can draw empty screen.
163 * and then update it after it gots update events
165 return DBOX_STATUS_ERROR_NONE;
169 if (read(fd, buffer->data, info->bufsz) != info->bufsz) {
170 ErrPrint("read: %s\n", strerror(errno));
172 ErrPrint("close: %s\n", strerror(errno));
177 * But return ZERO, even if we couldn't get a buffer file,
178 * the viewer can draw empty screen.
180 * and then update it after it gots update events
182 return DBOX_STATUS_ERROR_NONE;
187 ErrPrint("close: %s\n", strerror(errno));
189 return DBOX_STATUS_ERROR_NONE;
192 static int sync_for_pixmap(struct fb_info *info, int x, int y, int w, int h)
194 dynamicbox_fb_t buffer;
198 buffer = info->buffer;
199 if (!buffer) { /*!< Ignore this sync request */
200 return DBOX_STATUS_ERROR_NONE;
203 if (buffer->state != DBOX_FB_STATE_CREATED) {
204 ErrPrint("Invalid state of a FB\n");
205 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
208 if (buffer->type != DBOX_FB_TYPE_PIXMAP) {
209 ErrPrint("Invalid buffer\n");
210 return DBOX_STATUS_ERROR_NONE;
214 s_info.disp = XOpenDisplay(NULL);
218 s_info.disp_is_opened = 1;
220 screen = DefaultScreenOfDisplay(s_info.disp);
222 s_info.screen = DefaultScreen(s_info.disp);
223 s_info.visual = DefaultVisualOfScreen(screen);
225 ErrPrint("Failed to open a display\n");
226 return DBOX_STATUS_ERROR_FAULT;
230 if (info->handle == 0) {
231 ErrPrint("Pixmap ID is not valid\n");
232 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
235 if (info->bufsz == 0) {
237 * If the client does not acquire the buffer,
238 * This function will do nothing.
239 * It will work only if the buffer is acquired.
240 * To sync its contents.
242 DbgPrint("Nothing can be sync\n");
243 return DBOX_STATUS_ERROR_NONE;
246 si.shmid = shmget(IPC_PRIVATE, info->bufsz, IPC_CREAT | 0666);
248 ErrPrint("shmget: %s\n", strerror(errno));
249 return DBOX_STATUS_ERROR_FAULT;
253 si.shmaddr = shmat(si.shmid, NULL, 0);
254 if (si.shmaddr == (void *)-1) {
255 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
256 ErrPrint("shmctl: %s\n", strerror(errno));
259 return DBOX_STATUS_ERROR_FAULT;
264 * Use the 24 bits Pixmap for Video player
266 xim = XShmCreateImage(s_info.disp, s_info.visual,
267 (info->pixels << 3), ZPixmap, NULL,
271 if (shmdt(si.shmaddr) < 0) {
272 ErrPrint("shmdt: %s\n", strerror(errno));
275 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
276 ErrPrint("shmctl: %s\n", strerror(errno));
279 return DBOX_STATUS_ERROR_FAULT;
282 xim->data = si.shmaddr;
283 XShmAttach(s_info.disp, &si);
285 XShmGetImage(s_info.disp, info->handle, xim, 0, 0, 0xFFFFFFFF);
286 XSync(s_info.disp, False);
288 if (x != 0 || y != 0 || info->w != w || info->h != h) {
293 for (iy = y; iy < h; iy++) {
294 for (ix = x; ix < w; ix++) {
295 index = iy * info->w + x;
296 *(((unsigned int *)buffer->data) + index) = *(((unsigned int *)xim->data) + index);
300 memcpy(buffer->data, xim->data, info->bufsz);
303 XShmDetach(s_info.disp, &si);
306 if (shmdt(si.shmaddr) < 0) {
307 ErrPrint("shmdt: %s\n", strerror(errno));
310 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
311 ErrPrint("shmctl: %s\n", strerror(errno));
314 return DBOX_STATUS_ERROR_NONE;
317 int fb_sync(struct fb_info *info, int x, int y, int w, int h)
320 ErrPrint("FB Handle is not valid\n");
321 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
324 if (!info->id || info->id[0] == '\0') {
325 DbgPrint("Ingore sync\n");
326 return DBOX_STATUS_ERROR_NONE;
329 if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
330 return sync_for_file(info, x, y, w, h);
331 } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
332 return sync_for_pixmap(info, x, y, w, h);
333 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
334 /* No need to do sync */
335 return DBOX_STATUS_ERROR_NONE;
338 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
341 struct fb_info *fb_create(const char *id, int w, int h)
343 struct fb_info *info;
345 if (!id || id[0] == '\0') {
346 ErrPrint("Invalid ID\n");
350 info = calloc(1, sizeof(*info));
352 ErrPrint("Heap: %s\n", strerror(errno));
356 info->id = strdup(id);
358 ErrPrint("Heap: %s\n", strerror(errno));
363 info->pixels = sizeof(int); /* Use the default pixels(depth) */
365 if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
366 DbgPrint("SHMID: %d is gotten\n", info->handle);
367 } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) {
368 DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels);
370 info->handle = DBOX_STATUS_ERROR_INVALID_PARAMETER;
381 int fb_destroy(struct fb_info *info)
384 ErrPrint("Handle is not valid\n");
385 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
389 dynamicbox_fb_t buffer;
390 buffer = info->buffer;
397 return DBOX_STATUS_ERROR_NONE;
400 int fb_is_created(struct fb_info *info)
403 ErrPrint("Handle is not valid\n");
407 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) {
409 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) {
413 path = util_uri_to_path(info->id);
414 if (path && access(path, F_OK | R_OK) == 0) {
417 ErrPrint("access: %s (%s)\n", strerror(errno), path);
424 void *fb_acquire_buffer(struct fb_info *info)
426 dynamicbox_fb_t buffer;
429 ErrPrint("info == NIL\n");
430 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
435 if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
436 update_fb_size(info);
438 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
440 ErrPrint("Heap: %s\n", strerror(errno));
441 dynamicbox_set_last_status(DBOX_STATUS_ERROR_OUT_OF_MEMORY);
446 buffer->type = DBOX_FB_TYPE_PIXMAP;
448 buffer->state = DBOX_FB_STATE_CREATED;
450 info->buffer = buffer;
454 * Just update from here.
456 sync_for_pixmap(info, 0, 0, info->w, info->h);
457 } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
458 update_fb_size(info);
460 buffer = calloc(1, sizeof(*buffer) + info->bufsz);
462 ErrPrint("Heap: %s\n", strerror(errno));
464 dynamicbox_set_last_status(DBOX_STATUS_ERROR_OUT_OF_MEMORY);
468 buffer->type = DBOX_FB_TYPE_FILE;
470 buffer->state = DBOX_FB_STATE_CREATED;
472 info->buffer = buffer;
474 sync_for_file(info, 0, 0, info->w, info->h);
475 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
476 buffer = shmat(info->handle, NULL, 0);
477 if (buffer == (void *)-1) {
478 ErrPrint("shmat: %s (%d)\n", strerror(errno), info->handle);
479 dynamicbox_set_last_status(DBOX_STATUS_ERROR_FAULT);
485 ErrPrint("Buffer is not created (%s)\n", info->id);
486 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
491 buffer = info->buffer;
493 switch (buffer->type) {
494 case DBOX_FB_TYPE_PIXMAP:
497 case DBOX_FB_TYPE_FILE:
501 DbgPrint("Unknwon FP: %d\n", buffer->type);
502 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
509 int fb_release_buffer(void *data)
511 dynamicbox_fb_t buffer;
514 ErrPrint("buffer data == NIL\n");
515 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
516 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
519 buffer = container_of(data, struct dynamicbox_fb, data);
521 if (buffer->state != DBOX_FB_STATE_CREATED) {
522 ErrPrint("Invalid handle\n");
523 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
524 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
527 switch (buffer->type) {
528 case DBOX_FB_TYPE_SHM:
529 if (shmdt(buffer) < 0) {
530 ErrPrint("shmdt: %s\n", strerror(errno));
533 case DBOX_FB_TYPE_PIXMAP:
535 if (buffer->refcnt == 0) {
536 struct fb_info *info;
539 buffer->state = DBOX_FB_STATE_DESTROYED;
541 if (info && info->buffer == buffer) {
547 case DBOX_FB_TYPE_FILE:
549 if (buffer->refcnt == 0) {
550 struct fb_info *info;
553 buffer->state = DBOX_FB_STATE_DESTROYED;
555 if (info && info->buffer == buffer) {
563 ErrPrint("Unknwon buffer type\n");
564 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
568 return DBOX_STATUS_ERROR_NONE;
571 int fb_refcnt(void *data)
573 dynamicbox_fb_t buffer;
578 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
579 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
582 buffer = container_of(data, struct dynamicbox_fb, data);
584 if (buffer->state != DBOX_FB_STATE_CREATED) {
585 ErrPrint("Invalid handle\n");
586 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
587 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
590 switch (buffer->type) {
591 case DBOX_FB_TYPE_SHM:
592 if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) {
593 ErrPrint("Error: %s\n", strerror(errno));
594 dynamicbox_set_last_status(DBOX_STATUS_ERROR_FAULT);
595 return DBOX_STATUS_ERROR_FAULT;
598 ret = buf.shm_nattch;
600 case DBOX_FB_TYPE_PIXMAP:
601 ret = buffer->refcnt;
603 case DBOX_FB_TYPE_FILE:
604 ret = buffer->refcnt;
607 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
608 ret = DBOX_STATUS_ERROR_INVALID_PARAMETER;
615 const char *fb_id(struct fb_info *info)
617 return info ? info->id : NULL;
620 int fb_get_size(struct fb_info *info, int *w, int *h)
623 ErrPrint("Handle is not valid\n");
624 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
629 return DBOX_STATUS_ERROR_NONE;
632 int fb_size(struct fb_info *info)
635 dynamicbox_set_last_status(DBOX_STATUS_ERROR_INVALID_PARAMETER);
639 update_fb_size(info);
644 int fb_type(struct fb_info *info)
646 dynamicbox_fb_t buffer;
649 return DBOX_FB_TYPE_ERROR;
652 buffer = info->buffer;
654 int type = DBOX_FB_TYPE_ERROR;
657 * Try to get this from SCHEMA
660 if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
661 type = DBOX_FB_TYPE_FILE;
662 } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
663 type = DBOX_FB_TYPE_PIXMAP;
664 } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
665 type = DBOX_FB_TYPE_SHM;