c27eecf58e3460a0728d2fee30b6a8285b403710
[apps/livebox/data-provider-master.git] / src / buffer_handler.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 <unistd.h> /* access */
19 #include <sys/mman.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <sys/shm.h>
25 #include <sys/ipc.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include <Ecore.h>
30 #include <Ecore_X.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xproto.h>
34 #include <X11/extensions/Xdamage.h>
35 #include <X11/extensions/Xfixes.h>
36 #include <X11/extensions/XShm.h>
37
38 #include <dri2.h>
39 #include <xf86drm.h>
40 #include <xf86drmMode.h>
41 #include <tbm_bufmgr.h>
42
43 #include <dlog.h>
44 #include <packet.h>
45 #include <livebox-errno.h>
46
47 #include "debug.h"
48 #include "conf.h"
49 #include "util.h"
50 #include "instance.h"
51 #include "package.h"
52 #include "client_life.h"
53 #include "client_rpc.h"
54 #include "buffer_handler.h"
55 #include "script_handler.h" // Reverse dependency. must has to be broken
56
57 struct buffer {
58         enum {
59                 CREATED = 0x00beef00,
60                 DESTROYED = 0x00dead00
61         } state;
62         enum buffer_type type;
63         int refcnt;
64         void *info;
65         char data[];
66 };
67
68 /*!
69  * \brief Allocate this in the buffer->data.
70  */
71 struct gem_data {
72         DRI2Buffer *dri2_buffer;
73         unsigned int attachments[1];
74         tbm_bo pixmap_bo;
75         int count;
76         int buf_count;
77         int w;
78         int h;
79         int depth;
80         Pixmap pixmap;
81         void *data; /* Gem layer */
82         int refcnt;
83
84         void *compensate_data; /* Check the pitch value, copy this to data */
85 };
86
87 struct buffer_info
88 {
89         void *buffer;
90         char *id;
91         char *lock;
92         int lock_fd;
93
94         enum buffer_type type;
95
96         int w;
97         int h;
98         int pixel_size;
99         int is_loaded;
100
101         struct inst_info *inst;
102         void *data;
103 };
104
105 static struct {
106         tbm_bufmgr slp_bufmgr;
107         int evt_base;
108         int err_base;
109         int fd;
110         Eina_List *pixmap_list;
111 } s_info = {
112         .slp_bufmgr = NULL,
113         .evt_base = 0,
114         .err_base = 0,
115         .fd = -1,
116         .pixmap_list = NULL,
117 };
118
119 static int destroy_lock_file(struct buffer_info *info)
120 {
121         if (!info->inst) {
122                 return LB_STATUS_ERROR_INVALID;
123         }
124
125         if (!info->lock) {
126                 return LB_STATUS_ERROR_INVALID;
127         }
128
129         if (close(info->lock_fd) < 0) {
130                 ErrPrint("close: %s\n", strerror(errno));
131         }
132         info->lock_fd = -1;
133
134         if (unlink(info->lock) < 0) {
135                 ErrPrint("unlink: %s\n", strerror(errno));
136         }
137
138         DbgFree(info->lock);
139         info->lock = NULL;
140         return LB_STATUS_SUCCESS;
141 }
142
143 static int create_lock_file(struct buffer_info *info)
144 {
145         const char *id;
146         int len;
147         char *file;
148         char target[3] = "pd";
149
150         if (!info->inst) {
151                 return LB_STATUS_ERROR_INVALID;
152         }
153
154         id = instance_id(info->inst);
155         if (!id) {
156                 return LB_STATUS_ERROR_INVALID;
157         }
158
159         len = strlen(id);
160         file = malloc(len + 20);
161         if (!file) {
162                 ErrPrint("Heap: %s\n", strerror(errno));
163                 return LB_STATUS_ERROR_MEMORY;
164         }
165
166         if (script_handler_buffer_info(instance_pd_script(info->inst)) != info && instance_pd_buffer(info->inst) != info) {
167                 target[0] = 'l';
168                 target[1] = 'b';
169                 /* target[2] = '\0'; // We already have this ;) */
170         }
171
172         snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(id), target);
173         info->lock_fd = open(file, O_WRONLY|O_CREAT, 0644);
174         if (info->lock_fd < 0) {
175                 ErrPrint("open: %s\n", strerror(errno));
176                 DbgFree(file);
177                 return LB_STATUS_ERROR_IO;
178         }
179
180         info->lock = file;
181         return LB_STATUS_SUCCESS;
182 }
183
184 static int do_buffer_lock(struct buffer_info *buffer)
185 {
186         struct flock flock;
187         int ret;
188
189         if (buffer->lock_fd < 0) {
190                 return LB_STATUS_SUCCESS;
191         }
192
193         flock.l_type = F_WRLCK;
194         flock.l_whence = SEEK_SET;
195         flock.l_start = 0;
196         flock.l_len = 0;
197         flock.l_pid = getpid();
198
199         do {
200                 ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
201                 if (ret < 0) {
202                         ret = errno;
203                         ErrPrint("fcntl: %s\n", strerror(errno));
204                 }
205         } while (ret == EINTR);
206
207         return LB_STATUS_SUCCESS;
208 }
209
210 static int do_buffer_unlock(struct buffer_info *buffer)
211 {
212         struct flock flock;
213         int ret;
214
215         if (buffer->lock_fd < 0) {
216                 return LB_STATUS_SUCCESS;
217         }
218
219         flock.l_type = F_UNLCK;
220         flock.l_whence = SEEK_SET;
221         flock.l_start = 0;
222         flock.l_len = 0;
223         flock.l_pid = getpid();
224
225         do {
226                 ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
227                 if (ret < 0) {
228                         ret = errno;
229                         ErrPrint("fcntl: %s\n", strerror(errno));
230                 }
231         } while (ret == EINTR);
232
233         return LB_STATUS_SUCCESS;
234 }
235
236 static inline struct buffer *create_pixmap(struct buffer_info *info)
237 {
238         struct gem_data *gem;
239         struct buffer *buffer;
240         Display *disp;
241         Window parent;
242         XGCValues gcv;
243         GC gc;
244
245         disp = ecore_x_display_get();
246         if (!disp) {
247                 return NULL;
248         }
249
250         parent = DefaultRootWindow(disp);
251
252         buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
253         if (!buffer) {
254                 ErrPrint("Heap: %s\n", strerror(errno));
255                 return NULL;
256         }
257
258         gem = (struct gem_data *)buffer->data;
259
260         buffer->type = BUFFER_TYPE_PIXMAP;
261         buffer->refcnt = 1;
262         buffer->state = CREATED;
263
264         gem->attachments[0] = DRI2BufferFrontLeft;
265         gem->count = 1;
266         gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
267         gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
268         gem->depth = info->pixel_size;
269         /*!
270          * \NOTE
271          * Use the 24 Bits
272          * 32 Bits is not supported for video playing.
273          * But for the transparent background, use the 32 bits, and give up video.
274          */
275         gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
276         if (gem->pixmap == (Pixmap)0) {
277                 ErrPrint("Failed to create a pixmap\n");
278                 DbgFree(buffer);
279                 return NULL;
280         }
281
282         /*!
283          * \note
284          * Clear pixmap
285          */
286         memset(&gcv, 0, sizeof(gcv));
287         gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
288         if (gc) {
289                 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
290                 XSync(disp, False);
291                 XFreeGC(disp, gc);
292         } else {
293                 XSync(disp, False);
294                 ErrPrint("Unable to clear the pixmap\n");
295         }
296
297         return buffer;
298 }
299
300 static inline int create_gem(struct buffer *buffer)
301 {
302         struct gem_data *gem;
303         Display *disp;
304
305         disp = ecore_x_display_get();
306         if (!disp) {
307                 ErrPrint("Failed to get display\n");
308                 return LB_STATUS_ERROR_IO;
309         }
310
311         gem = (struct gem_data *)buffer->data;
312
313         if (s_info.fd < 0) {
314                 gem->data = calloc(1, gem->w * gem->h * gem->depth);
315                 if (!gem->data) {
316                         ErrPrint("Heap: %s\n", strerror(errno));
317                         return LB_STATUS_ERROR_MEMORY;
318                 }
319
320                 ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
321                 return LB_STATUS_SUCCESS;
322         }
323
324         DRI2CreateDrawable(disp, gem->pixmap);
325
326         gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
327                                         &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
328         if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
329                 ErrPrint("Failed to get a gem buffer\n");
330                 DRI2DestroyDrawable(disp, gem->pixmap);
331                 return LB_STATUS_ERROR_FAULT;
332         }
333         /*!
334          * \How can I destroy this?
335          */
336         gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
337         if (!gem->pixmap_bo) {
338                 ErrPrint("Failed to import BO\n");
339                 DRI2DestroyDrawable(disp, gem->pixmap);
340                 return LB_STATUS_ERROR_FAULT;
341         }
342
343         if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
344                 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
345                 if (!gem->compensate_data) {
346                         ErrPrint("Failed to allocate heap\n");
347                 }
348         }
349
350         DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p\n",
351                                 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
352                                 gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data);
353
354         return LB_STATUS_SUCCESS;
355 }
356
357 static inline void *acquire_gem(struct buffer *buffer)
358 {
359         struct gem_data *gem;
360
361         if (!buffer) {
362                 return NULL;
363         }
364
365         gem = (struct gem_data *)buffer->data;
366         if (s_info.fd < 0) {
367                 ErrPrint("GEM is not supported - Use the fake gem buffer\n");
368         } else {
369                 if (!gem->pixmap_bo) {
370                         ErrPrint("GEM is not created\n");
371                         return NULL;
372                 }
373
374                 if (!gem->data) {
375                         tbm_bo_handle handle;
376
377                         if (gem->refcnt) {
378                                 ErrPrint("Already acquired. but the buffer is not valid\n");
379                                 return NULL;
380                         }
381
382                         handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
383                         gem->data = handle.ptr;
384                 }
385         }
386
387         gem->refcnt++;
388
389         /*!
390          * \note
391          * If there is a compensate canvas buffer,
392          * use it
393          */
394         return gem->compensate_data ? gem->compensate_data : gem->data;
395 }
396
397 static inline void release_gem(struct buffer *buffer)
398 {
399         struct gem_data *gem;
400
401         gem = (struct gem_data *)buffer->data;
402         if (s_info.fd >= 0 && !gem->pixmap_bo) {
403                 ErrPrint("GEM is not created\n");
404                 return;
405         }
406
407         if (!gem->data) {
408                 if (gem->refcnt > 0) {
409                         ErrPrint("Reference count is not valid %d\n", gem->refcnt);
410                         gem->refcnt = 0;
411                 }
412                 return;
413         }
414
415         gem->refcnt--;
416         if (gem->refcnt == 0) {
417                 if (s_info.fd < 0) {
418                         DbgPrint("S/W Gem buffer has no reference\n");
419                 } else {
420                         /*!
421                          * \note
422                          * Update the gem buffer using compensate data buffer if it is exists
423                          */
424                         if (gem->compensate_data) {
425                                 register int x;
426                                 register int y;
427                                 int *gem_pixel;
428                                 int *pixel;
429                                 int gap;
430
431                                 pixel = gem->compensate_data;
432                                 gem_pixel = gem->data;
433                                 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
434
435                                 for (y = 0; y < gem->h; y++) {
436                                         for (x = 0; x < gem->w; x++) {
437                                                 *gem_pixel++ = *pixel++;
438                                         }
439
440                                         gem_pixel = (int *)(((char *)gem_pixel) + gap);
441                                 }
442                         }
443
444                         if (gem->pixmap_bo) {
445                                 tbm_bo_unmap(gem->pixmap_bo);
446                         }
447
448                         gem->data = NULL;
449                 }
450         } else if (gem->refcnt < 0) {
451                 ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
452                 gem->refcnt = 0;
453         }
454 }
455
456 static inline int destroy_pixmap(struct buffer *buffer)
457 {
458         struct gem_data *gem;
459
460         gem = (struct gem_data *)buffer->data;
461
462         if (gem->pixmap) {
463                 Display *disp;
464
465                 disp = ecore_x_display_get();
466                 if (!disp) {
467                         return LB_STATUS_ERROR_IO;
468                 }
469
470                 DbgPrint("pixmap %lu\n", gem->pixmap);
471                 XFreePixmap(disp, gem->pixmap);
472         }
473
474         buffer->state = DESTROYED;
475         DbgFree(buffer);
476         return LB_STATUS_SUCCESS;
477 }
478
479 static inline int destroy_gem(struct buffer *buffer)
480 {
481         struct gem_data *gem;
482
483         if (!buffer) {
484                 return LB_STATUS_ERROR_INVALID;
485         }
486
487         /*!
488          * Forcely release the acquire_buffer.
489          */
490         gem = (struct gem_data *)buffer->data;
491         if (!gem) {
492                 return LB_STATUS_ERROR_FAULT;
493         }
494
495         if (s_info.fd >= 0) {
496                 if (gem->compensate_data) {
497                         DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
498                         DbgFree(gem->compensate_data);
499                         gem->compensate_data = NULL;
500                 }
501
502                 if (gem->pixmap_bo) {
503                         DbgPrint("unref pixmap bo\n");
504                         tbm_bo_unref(gem->pixmap_bo);
505                         gem->pixmap_bo = NULL;
506
507                         DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
508                 }
509         } else if (gem->data) {
510                 DbgPrint("Release fake gem buffer\n");
511                 DbgFree(gem->data);
512                 gem->data = NULL;
513         }
514
515         return LB_STATUS_SUCCESS;
516 }
517
518 static inline int load_file_buffer(struct buffer_info *info)
519 {
520         struct buffer *buffer;
521         double timestamp;
522         int size;
523         char *new_id;
524         int len;
525
526         len = strlen(IMAGE_PATH) + 40;
527         new_id = malloc(len);
528         if (!new_id) {
529                 ErrPrint("Heap: %s\n", strerror(errno));
530                 return LB_STATUS_ERROR_MEMORY;
531         }
532
533         timestamp = util_timestamp();
534         snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
535
536         size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
537         if (!size) {
538                 ErrPrint("Canvas buffer size is ZERO\n");
539                 DbgFree(new_id);
540                 return LB_STATUS_ERROR_INVALID;
541         }
542
543         buffer = calloc(1, size);
544         if (!buffer) {
545                 ErrPrint("Failed to allocate buffer\n");
546                 DbgFree(new_id);
547                 return LB_STATUS_ERROR_MEMORY;
548         }
549
550         buffer->type = BUFFER_TYPE_FILE;
551         buffer->refcnt = 0;
552         buffer->state = CREATED;
553         buffer->info = info;
554
555         DbgFree(info->id);
556         info->id = new_id;
557         info->buffer = buffer;
558         info->is_loaded = 1;
559
560         DbgPrint("FILE type %d created\n", size);
561         return LB_STATUS_SUCCESS;
562 }
563
564 static inline int load_shm_buffer(struct buffer_info *info)
565 {
566         int id;
567         int size;
568         struct buffer *buffer; /* Just for getting a size */
569         char *new_id;
570         int len;
571
572         size = info->w * info->h * info->pixel_size;
573         if (!size) {
574                 ErrPrint("Invalid buffer size\n");
575                 return LB_STATUS_ERROR_INVALID;
576         }
577
578         id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
579         if (id < 0) {
580                 ErrPrint("shmget: %s\n", strerror(errno));
581                 return LB_STATUS_ERROR_FAULT;
582         }
583
584         buffer = shmat(id, NULL, 0);
585         if (buffer == (void *)-1) {
586                 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
587
588                 if (shmctl(id, IPC_RMID, 0) < 0) {
589                         ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
590                 }
591
592                 return LB_STATUS_ERROR_FAULT;
593         }
594
595         buffer->type = BUFFER_TYPE_SHM;
596         buffer->refcnt = id;
597         buffer->state = CREATED; /*!< Needless */
598         buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
599
600         len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
601
602         new_id = malloc(len);
603         if (!new_id) {
604                 ErrPrint("Heap: %s\n", strerror(errno));
605                 if (shmdt(buffer) < 0) {
606                         ErrPrint("shmdt: %s\n", strerror(errno));
607                 }
608
609                 if (shmctl(id, IPC_RMID, 0) < 0) {
610                         ErrPrint("shmctl: %s\n", strerror(errno));
611                 }
612
613                 return LB_STATUS_ERROR_MEMORY;
614         }
615
616         snprintf(new_id, len, SCHEMA_SHM "%d", id);
617
618         DbgFree(info->id);
619         info->id = new_id;
620         info->buffer = buffer;
621         info->is_loaded = 1;
622         return LB_STATUS_SUCCESS;
623 }
624
625 static inline int load_pixmap_buffer(struct buffer_info *info)
626 {
627         struct buffer *buffer;
628         struct gem_data *gem;
629         char *new_id;
630         int len;
631
632         /*!
633          * \NOTE
634          * Before call the buffer_handler_pixmap_ref function,
635          * You should make sure that the is_loaded value is toggled (1)
636          * Or the buffer_handler_pixmap_ref function will return NULL
637          */
638         info->is_loaded = 1;
639
640         if (info->buffer) {
641                 DbgPrint("Buffer is already exists, but override it with new one\n");
642         }
643
644         buffer = buffer_handler_pixmap_ref(info);
645         if (!buffer) {
646                 DbgPrint("Failed to make a reference of a pixmap\n");
647                 info->is_loaded = 0;
648                 return LB_STATUS_ERROR_FAULT;
649         }
650
651         len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
652         new_id = malloc(len);
653         if (!new_id) {
654                 ErrPrint("Heap: %s\n", strerror(errno));
655                 info->is_loaded = 0;
656                 buffer_handler_pixmap_unref(buffer);
657                 return LB_STATUS_ERROR_MEMORY;
658         }
659
660         DbgFree(info->id);
661         info->id = new_id;
662
663         gem = (struct gem_data *)buffer->data;
664
665         snprintf(info->id, len, SCHEMA_PIXMAP "%d:%d", (int)gem->pixmap, info->pixel_size);
666         DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
667         return LB_STATUS_SUCCESS;
668 }
669
670 EAPI int buffer_handler_load(struct buffer_info *info)
671 {
672         int ret;
673
674         if (!info) {
675                 ErrPrint("buffer handler is nil\n");
676                 return LB_STATUS_ERROR_INVALID;
677         }
678
679         if (info->is_loaded) {
680                 DbgPrint("Buffer is already loaded\n");
681                 return LB_STATUS_SUCCESS;
682         }
683
684         switch (info->type) {
685         case BUFFER_TYPE_FILE:
686                 ret = load_file_buffer(info);
687                 (void)create_lock_file(info);
688                 break;
689         case BUFFER_TYPE_SHM:
690                 ret = load_shm_buffer(info);
691                 (void)create_lock_file(info);
692                 break;
693         case BUFFER_TYPE_PIXMAP:
694                 ret = load_pixmap_buffer(info);
695                 break;
696         default:
697                 ErrPrint("Invalid buffer\n");
698                 ret = LB_STATUS_ERROR_INVALID;
699                 break;
700         }
701
702         return ret;
703 }
704
705 static inline int unload_file_buffer(struct buffer_info *info)
706 {
707         const char *path;
708         char *new_id;
709
710         new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
711         if (!new_id) {
712                 ErrPrint("Heap: %s\n", strerror(errno));
713                 return LB_STATUS_ERROR_MEMORY;
714         }
715
716         DbgFree(info->buffer);
717         info->buffer = NULL;
718
719         path = util_uri_to_path(info->id);
720         if (path && unlink(path) < 0) {
721                 ErrPrint("unlink: %s\n", strerror(errno));
722         }
723
724         DbgFree(info->id);
725         info->id = new_id;
726         return LB_STATUS_SUCCESS;
727 }
728
729 static inline int unload_shm_buffer(struct buffer_info *info)
730 {
731         int id;
732         char *new_id;
733
734         new_id = strdup(SCHEMA_SHM "-1");
735         if (!new_id) {
736                 ErrPrint("Heap: %s\n", strerror(errno));
737                 return LB_STATUS_ERROR_MEMORY;
738         }
739
740         if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
741                 ErrPrint("%s Invalid ID\n", info->id);
742                 DbgFree(new_id);
743                 return LB_STATUS_ERROR_INVALID;
744         }
745
746         if (id < 0) {
747                 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
748                 DbgFree(new_id);
749                 return LB_STATUS_ERROR_INVALID;
750         }
751
752         if (shmdt(info->buffer) < 0) {
753                 ErrPrint("Detach shm: %s\n", strerror(errno));
754         }
755
756         if (shmctl(id, IPC_RMID, 0) < 0) {
757                 ErrPrint("Remove shm: %s\n", strerror(errno));
758         }
759
760         info->buffer = NULL;
761
762         DbgFree(info->id);
763         info->id = new_id;
764         return LB_STATUS_SUCCESS;
765 }
766
767 static inline int unload_pixmap_buffer(struct buffer_info *info)
768 {
769         int id;
770         char *new_id;
771         int pixels;
772
773         new_id = strdup(SCHEMA_PIXMAP "0:0");
774         if (!new_id) {
775                 ErrPrint("Heap: %s\n", strerror(errno));
776                 return LB_STATUS_ERROR_MEMORY;
777         }
778
779         if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &id, &pixels) != 2) {
780                 ErrPrint("Invalid ID (%s)\n", info->id);
781                 DbgFree(new_id);
782                 return LB_STATUS_ERROR_INVALID;
783         }
784
785         if (id == 0) {
786                 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
787                 DbgFree(new_id);
788                 return LB_STATUS_ERROR_INVALID;
789         }
790
791         /*!
792          * Decrease the reference counter.
793          */
794         buffer_handler_pixmap_unref(info->buffer);
795
796         /*!
797          * \note
798          * Just clear the info->buffer.
799          * It will be reallocated again.
800          */
801         info->buffer = NULL;
802
803         DbgFree(info->id);
804         info->id = new_id;
805         return LB_STATUS_SUCCESS;
806 }
807
808 EAPI int buffer_handler_unload(struct buffer_info *info)
809 {
810         int ret;
811
812         if (!info) {
813                 ErrPrint("buffer handler is NIL\n");
814                 return LB_STATUS_ERROR_INVALID;
815         }
816
817         if (!info->is_loaded) {
818                 ErrPrint("Buffer is not loaded\n");
819                 return LB_STATUS_ERROR_INVALID;
820         }
821
822         switch (info->type) {
823         case BUFFER_TYPE_FILE:
824                 (void)destroy_lock_file(info);
825                 ret = unload_file_buffer(info);
826                 break;
827         case BUFFER_TYPE_SHM:
828                 (void)destroy_lock_file(info);
829                 ret = unload_shm_buffer(info);
830                 break;
831         case BUFFER_TYPE_PIXMAP:
832                 ret = unload_pixmap_buffer(info);
833                 break;
834         default:
835                 ErrPrint("Invalid buffer\n");
836                 ret = LB_STATUS_ERROR_INVALID;
837                 break;
838         }
839
840         if (ret == 0) {
841                 info->is_loaded = 0;
842         }
843
844         return ret;
845 }
846
847 EAPI const char *buffer_handler_id(const struct buffer_info *info)
848 {
849         return info ? info->id : "";
850 }
851
852 EAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
853 {
854         return info ? info->type : BUFFER_TYPE_ERROR;
855 }
856
857 EAPI void *buffer_handler_fb(struct buffer_info *info)
858 {
859         struct buffer *buffer;
860
861         if (!info) {
862                 return NULL;
863         }
864
865         buffer = info->buffer;
866
867         if (info->type == BUFFER_TYPE_PIXMAP) {
868                 void *canvas;
869                 int ret;
870
871                 /*!
872                  * \note
873                  * For getting the buffer address of gem.
874                  */
875                 canvas = buffer_handler_pixmap_acquire_buffer(info);
876                 ret = buffer_handler_pixmap_release_buffer(canvas);
877                 if (ret < 0) {
878                         ErrPrint("Failed to release buffer: %d\n", ret);
879                 }
880                 return canvas;
881         }
882
883         return buffer->data;
884 }
885
886 EAPI int buffer_handler_pixmap(const struct buffer_info *info)
887 {
888         struct buffer *buf;
889         struct gem_data *gem;
890
891         if (!info) {
892                 ErrPrint("Inavlid buffer handler\n");
893                 return 0;
894         }
895
896         if (info->type != BUFFER_TYPE_PIXMAP) {
897                 ErrPrint("Invalid buffer type\n");
898                 return 0;
899         }
900
901         buf = (struct buffer *)info->buffer;
902         if (!buf) {
903                 ErrPrint("Invalid buffer data\n");
904                 return 0;
905         }
906
907         gem = (struct gem_data *)buf->data;
908         return gem->pixmap;
909 }
910
911 EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
912 {
913         struct buffer *buffer;
914
915         if (!info || !info->is_loaded) {
916                 ErrPrint("Buffer is not loaded\n");
917                 return NULL;
918         }
919
920         buffer = buffer_handler_pixmap_ref(info);
921         if (!buffer) {
922                 return NULL;
923         }
924
925         return acquire_gem(buffer);
926 }
927
928 EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
929 {
930         struct buffer *buffer;
931         struct gem_data *gem;
932
933         if (!info) {
934                 return NULL;
935         }
936
937         if (!info->is_loaded) {
938                 ErrPrint("Buffer is not loaded\n");
939                 return NULL;
940         }
941
942         buffer = info->buffer;
943         if (!buffer) {
944                 return NULL;
945         }
946
947         gem = (struct gem_data *)buffer->data;
948         return gem->compensate_data ? gem->compensate_data : gem->data;
949 }
950
951 /*!
952  * \return "buffer" object (Not the buffer_info)
953  */
954 EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
955 {
956         struct buffer *buffer;
957
958         if (!info->is_loaded) {
959                 ErrPrint("Buffer is not loaded\n");
960                 return NULL;
961         }
962
963         if (info->type != BUFFER_TYPE_PIXMAP) {
964                 ErrPrint("Buffer type is not matched\n");
965                 return NULL;
966         }
967
968         buffer = info->buffer;
969         if (!buffer) {
970                 int need_gem = 1;
971
972                 buffer = create_pixmap(info);
973                 if (!buffer) {
974                         ErrPrint("Failed to create a pixmap\n");
975                         return NULL;
976                 }
977
978                 info->buffer = buffer;
979
980                 if (info->inst) {
981                         struct pkg_info *pkg;
982
983                         if (instance_lb_buffer(info->inst) == info) {
984                                 pkg = instance_package(info->inst);
985                                 if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
986                                         need_gem = 0;
987                                 }
988                         } else if (instance_pd_buffer(info->inst) == info) {
989                                 pkg = instance_package(info->inst);
990                                 if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
991                                         need_gem = 0;
992                                 }
993                         }
994                 }
995
996                 if (need_gem) {
997                         create_gem(buffer);
998                 }
999
1000         } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1001                 ErrPrint("Invalid buffer\n");
1002                 return NULL;
1003         } else if (buffer->refcnt > 0) {
1004                 buffer->refcnt++;
1005                 return buffer;
1006         }
1007
1008         s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
1009         return buffer;
1010 }
1011
1012 /*!
1013  * \return "buffer"
1014  */
1015 EAPI void *buffer_handler_pixmap_find(int pixmap)
1016 {
1017         struct buffer *buffer;
1018         struct gem_data *gem;
1019         Eina_List *l;
1020         Eina_List *n;
1021
1022         if (pixmap == 0) {
1023                 return NULL;
1024         }
1025
1026         EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
1027                 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1028                         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1029                         DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
1030                         continue;
1031                 }
1032
1033                 gem = (struct gem_data *)buffer->data;
1034                 if (gem->pixmap == pixmap) {
1035                         return buffer;
1036                 }
1037         }
1038
1039         return NULL;
1040 }
1041
1042 EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
1043 {
1044         struct buffer *buffer;
1045         struct gem_data *gem;
1046         Eina_List *l;
1047         Eina_List *n;
1048         void *_ptr;
1049
1050         if (!canvas) {
1051                 return LB_STATUS_ERROR_INVALID;
1052         }
1053
1054         EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
1055                 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1056                         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1057                         continue;
1058                 }
1059
1060                 gem = (struct gem_data *)buffer->data;
1061                 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
1062
1063                 if (!_ptr) {
1064                         continue;
1065                 }
1066
1067                 if (_ptr == canvas) {
1068                         release_gem(buffer);
1069                         buffer_handler_pixmap_unref(buffer);
1070                         return LB_STATUS_SUCCESS;
1071                 }
1072         }
1073
1074         return LB_STATUS_ERROR_NOT_EXIST;
1075 }
1076
1077 /*!
1078  * \note
1079  *
1080  * \return Return NULL if the buffer is in still uses.
1081  *         Return buffer_ptr if it needs to destroy
1082  */
1083 EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
1084 {
1085         struct buffer *buffer = buffer_ptr;
1086         struct buffer_info *info;
1087
1088         buffer->refcnt--;
1089         if (buffer->refcnt > 0) {
1090                 return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
1091         }
1092
1093         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1094
1095         info = buffer->info;
1096
1097         if (destroy_gem(buffer) < 0) {
1098                 ErrPrint("Failed to destroy gem buffer\n");
1099         }
1100
1101         if (destroy_pixmap(buffer) < 0) {
1102                 ErrPrint("Failed to destroy pixmap\n");
1103         }
1104
1105         if (info && info->buffer == buffer) {
1106                 info->buffer = NULL;
1107         }
1108
1109         return LB_STATUS_SUCCESS;
1110 }
1111
1112 EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1113 {
1114         return info ? info->is_loaded : 0;
1115 }
1116
1117 EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1118 {
1119         if (!info) {
1120                 return;
1121         }
1122
1123         info->w = w;
1124         info->h = h;
1125 }
1126
1127 EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1128 {
1129         int ret;
1130
1131         if (!info) {
1132                 ErrPrint("Invalid handler\n");
1133                 return LB_STATUS_ERROR_INVALID;
1134         }
1135
1136         if (info->w == w && info->h == h) {
1137                 DbgPrint("No changes\n");
1138                 return LB_STATUS_SUCCESS;
1139         }
1140
1141         buffer_handler_update_size(info, w, h);
1142
1143         if (!info->is_loaded) {
1144                 DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
1145                 return LB_STATUS_SUCCESS;
1146         }
1147
1148         ret = buffer_handler_unload(info);
1149         if (ret < 0) {
1150                 ErrPrint("Unload: %d\n", ret);
1151         }
1152
1153         ret = buffer_handler_load(info);
1154         if (ret < 0) {
1155                 ErrPrint("Load: %d\n", ret);
1156         }
1157
1158         return LB_STATUS_SUCCESS;
1159 }
1160
1161 EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1162 {
1163         if (!info) {
1164                 return LB_STATUS_ERROR_INVALID;
1165         }
1166
1167         if (w) {
1168                 *w = info->w;
1169         }
1170         if (h) {
1171                 *h = info->h;
1172         }
1173
1174         return LB_STATUS_SUCCESS;
1175 }
1176
1177 EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1178 {
1179         return info->inst;
1180 }
1181
1182 /*!
1183  * \note
1184  * Only for used S/W Backend
1185  */
1186 static inline int sync_for_pixmap(struct buffer *buffer)
1187 {
1188         XShmSegmentInfo si;
1189         XImage *xim;
1190         GC gc;
1191         Display *disp;
1192         struct gem_data *gem;
1193         Screen *screen;
1194         Visual *visual;
1195
1196         if (buffer->state != CREATED) {
1197                 ErrPrint("Invalid state of a FB\n");
1198                 return LB_STATUS_ERROR_INVALID;
1199         }
1200
1201         if (buffer->type != BUFFER_TYPE_PIXMAP) {
1202                 ErrPrint("Invalid buffer\n");
1203                 return LB_STATUS_SUCCESS;
1204         }
1205
1206         disp = ecore_x_display_get();
1207         if (!disp) {
1208                 ErrPrint("Failed to get a display\n");
1209                 return LB_STATUS_ERROR_FAULT;
1210         }
1211
1212         gem = (struct gem_data *)buffer->data;
1213         if (gem->w == 0 || gem->h == 0) {
1214                 DbgPrint("Nothing can be sync\n");
1215                 return LB_STATUS_SUCCESS;
1216         }
1217
1218         si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1219         if (si.shmid < 0) {
1220                 ErrPrint("shmget: %s\n", strerror(errno));
1221                 return LB_STATUS_ERROR_FAULT;
1222         }
1223
1224         si.readOnly = False;
1225         si.shmaddr = shmat(si.shmid, NULL, 0);
1226         if (si.shmaddr == (void *)-1) {
1227                 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1228                         ErrPrint("shmctl: %s\n", strerror(errno));
1229                 }
1230                 return LB_STATUS_ERROR_FAULT;
1231         }
1232
1233         screen = DefaultScreenOfDisplay(disp);
1234         visual = DefaultVisualOfScreen(screen);
1235         /*!
1236          * \NOTE
1237          * XCreatePixmap can only uses 24 bits depth only.
1238          */
1239         xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1240         if (xim == NULL) {
1241                 if (shmdt(si.shmaddr) < 0) {
1242                         ErrPrint("shmdt: %s\n", strerror(errno));
1243                 }
1244
1245                 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1246                         ErrPrint("shmctl: %s\n", strerror(errno));
1247                 }
1248                 return LB_STATUS_ERROR_FAULT;
1249         }
1250
1251         xim->data = si.shmaddr;
1252         XShmAttach(disp, &si);
1253         XSync(disp, False);
1254
1255         gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1256         if (!gc) {
1257                 XShmDetach(disp, &si);
1258                 XDestroyImage(xim);
1259
1260                 if (shmdt(si.shmaddr) < 0) {
1261                         ErrPrint("shmdt: %s\n", strerror(errno));
1262                 }
1263
1264                 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1265                         ErrPrint("shmctl: %s\n", strerror(errno));
1266                 }
1267
1268                 return LB_STATUS_ERROR_FAULT;
1269         }
1270
1271         memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
1272
1273         /*!
1274          * \note Do not send the event.
1275          *       Instead of X event, master will send the updated event to the viewer
1276          */
1277         XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
1278         XSync(disp, False);
1279
1280         XFreeGC(disp, gc);
1281         XShmDetach(disp, &si);
1282         XDestroyImage(xim);
1283
1284         if (shmdt(si.shmaddr) < 0) {
1285                 ErrPrint("shmdt: %s\n", strerror(errno));
1286         }
1287
1288         if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1289                 ErrPrint("shmctl: %s\n", strerror(errno));
1290         }
1291
1292         return LB_STATUS_SUCCESS;
1293 }
1294
1295 EAPI void buffer_handler_flush(struct buffer_info *info)
1296 {
1297         int fd;
1298         int size;
1299         struct buffer *buffer;
1300
1301         if (!info || !info->buffer) {
1302                 return;
1303         }
1304
1305         buffer = info->buffer;
1306
1307         if (buffer->type == BUFFER_TYPE_PIXMAP) {
1308                 if (s_info.fd > 0) {
1309                         //return;
1310                         //PERF_INIT();
1311                         //PERF_BEGIN();
1312                         XRectangle rect;
1313                         XserverRegion region;
1314
1315                         rect.x = 0;
1316                         rect.y = 0;
1317                         rect.width = info->w;
1318                         rect.height = info->h;
1319
1320                         region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1321                         XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1322                         XFixesDestroyRegion(ecore_x_display_get(), region);
1323                         XFlush(ecore_x_display_get());
1324                         //PERF_MARK("XFlush");
1325                 } else {
1326                         if (sync_for_pixmap(buffer) < 0) {
1327                                 ErrPrint("Failed to sync via S/W Backend\n");
1328                         }
1329                 }
1330         } else if (buffer->type == BUFFER_TYPE_FILE) {
1331                 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1332                 if (fd < 0) {
1333                         ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1334                         return;
1335                 }
1336
1337                 size = info->w * info->h * info->pixel_size;
1338                 do_buffer_lock(info);
1339                 if (write(fd, info->buffer, size) != size) {
1340                         ErrPrint("Write is not completed: %s\n", strerror(errno));
1341                 }
1342                 do_buffer_unlock(info);
1343
1344                 if (close(fd) < 0) {
1345                         ErrPrint("close: %s\n", strerror(errno));
1346                 }
1347         } else {
1348                 DbgPrint("Flush nothing\n");
1349         }
1350 }
1351
1352 HAPI int buffer_handler_init(void)
1353 {
1354         int dri2Major, dri2Minor;
1355         char *driverName, *deviceName;
1356         drm_magic_t magic;
1357
1358         if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1359                 ErrPrint("DRI2 is not supported\n");
1360                 return LB_STATUS_SUCCESS;
1361         }
1362
1363         if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1364                 ErrPrint("DRI2 is not supported\n");
1365                 s_info.evt_base = 0;
1366                 s_info.err_base = 0;
1367                 return LB_STATUS_SUCCESS;
1368         }
1369
1370         if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1371                 ErrPrint("DRI2 is not supported\n");
1372                 s_info.evt_base = 0;
1373                 s_info.err_base = 0;
1374                 return LB_STATUS_SUCCESS;
1375         }
1376
1377         if (USE_SW_BACKEND) {
1378                 DbgPrint("Fallback to the S/W Backend\n");
1379                 s_info.evt_base = 0;
1380                 s_info.err_base = 0;
1381                 DbgFree(deviceName);
1382                 DbgFree(driverName);
1383                 return LB_STATUS_SUCCESS;
1384         }
1385
1386         s_info.fd = open(deviceName, O_RDWR);
1387         DbgFree(deviceName);
1388         DbgFree(driverName);
1389         if (s_info.fd < 0) {
1390                 ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1391                 s_info.evt_base = 0;
1392                 s_info.err_base = 0;
1393                 return LB_STATUS_SUCCESS;
1394         }
1395
1396         drmGetMagic(s_info.fd, &magic);
1397         DbgPrint("DRM Magic: 0x%X\n", magic);
1398         if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1399                 ErrPrint("Failed to do authenticate for DRI2\n");
1400                 if (close(s_info.fd) < 0) {
1401                         ErrPrint("close: %s\n", strerror(errno));
1402                 }
1403                 s_info.fd = -1;
1404                 s_info.evt_base = 0;
1405                 s_info.err_base = 0;
1406                 return LB_STATUS_SUCCESS;
1407         }
1408
1409         s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1410         if (!s_info.slp_bufmgr) {
1411                 ErrPrint("Failed to init bufmgr\n");
1412                 if (close(s_info.fd) < 0) {
1413                         ErrPrint("close: %s\n", strerror(errno));
1414                 }
1415                 s_info.fd = -1;
1416                 s_info.evt_base = 0;
1417                 s_info.err_base = 0;
1418                 return LB_STATUS_SUCCESS;
1419         }
1420
1421         return LB_STATUS_SUCCESS;
1422 }
1423
1424 HAPI int buffer_handler_fini(void)
1425 {
1426         if (s_info.fd >= 0) {
1427                 if (close(s_info.fd) < 0) {
1428                         ErrPrint("close: %s\n", strerror(errno));
1429                 }
1430                 s_info.fd = -1;
1431         }
1432
1433         if (s_info.slp_bufmgr) {
1434                 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1435                 s_info.slp_bufmgr = NULL;
1436         }
1437
1438         return LB_STATUS_SUCCESS;
1439 }
1440
1441 static inline struct buffer *raw_open_file(const char *filename)
1442 {
1443         struct buffer *buffer;
1444         int fd;
1445         off_t off;
1446         int ret;
1447
1448         fd = open(filename, O_RDONLY);
1449         if (fd < 0) {
1450                 ErrPrint("open: %s\n", strerror(errno));
1451                 return NULL;
1452         }
1453
1454         off = lseek(fd, 0L, SEEK_END);
1455         if (off == (off_t)-1) {
1456                 ErrPrint("lseek: %s\n", strerror(errno));
1457
1458                 if (close(fd) < 0) {
1459                         ErrPrint("close: %s\n", strerror(errno));
1460                 }
1461
1462                 return NULL;
1463         }
1464
1465         if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
1466                 ErrPrint("lseek: %s\n", strerror(errno));
1467
1468                 if (close(fd) < 0) {
1469                         ErrPrint("close: %s\n", strerror(errno));
1470                 }
1471
1472                 return NULL;
1473         }
1474
1475         buffer = calloc(1, sizeof(*buffer) + off);
1476         if (!buffer) {
1477                 ErrPrint("Heap: %s\n", strerror(errno));
1478
1479                 if (close(fd) < 0) {
1480                         ErrPrint("close: %s\n", strerror(errno));
1481                 }
1482
1483                 return NULL;
1484         }
1485
1486         buffer->state = CREATED;
1487         buffer->type = BUFFER_TYPE_FILE;
1488         buffer->refcnt = 0;
1489         buffer->info = (void *)off;
1490
1491         ret = read(fd, buffer->data, off);
1492         if (ret < 0) {
1493                 ErrPrint("read: %s\n", strerror(errno));
1494                 DbgFree(buffer);
1495
1496                 if (close(fd) < 0) {
1497                         ErrPrint("close: %s\n", strerror(errno));
1498                 }
1499
1500                 return NULL;
1501         }
1502
1503         if (close(fd) < 0) {
1504                 ErrPrint("close: %s\n", strerror(errno));
1505         }
1506
1507         return buffer;
1508 }
1509
1510 static inline int raw_close_file(struct buffer *buffer)
1511 {
1512         DbgFree(buffer);
1513         return 0;
1514 }
1515
1516 static inline struct buffer *raw_open_shm(int shm)
1517 {
1518         struct buffer *buffer;
1519
1520         buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
1521         if (buffer == (struct buffer *)-1) {
1522                 ErrPrint("shmat: %s\n", strerror(errno));
1523                 return NULL;
1524         }
1525
1526         return buffer;
1527 }
1528
1529 static inline int raw_close_shm(struct buffer *buffer)
1530 {
1531         int ret;
1532
1533         ret = shmdt(buffer);
1534         if (ret < 0) {
1535                 ErrPrint("shmdt: %s\n", strerror(errno));
1536         }
1537
1538         return ret;
1539 }
1540
1541 static inline struct buffer *raw_open_pixmap(unsigned int pixmap)
1542 {
1543         struct buffer *buffer;
1544
1545         buffer = calloc(1, sizeof(*buffer) + DEFAULT_PIXELS);
1546         if (!buffer) {
1547                 ErrPrint("Heap: %s\n", strerror(errno));
1548                 return NULL;
1549         }
1550
1551         buffer->state = CREATED;
1552         buffer->type = BUFFER_TYPE_PIXMAP;
1553
1554         return buffer;
1555 }
1556
1557 static inline int raw_close_pixmap(struct buffer *buffer)
1558 {
1559         DbgFree(buffer);
1560         return 0;
1561 }
1562
1563 EAPI void *buffer_handler_raw_data(struct buffer *buffer)
1564 {
1565         if (!buffer || buffer->state != CREATED) {
1566                 return NULL;
1567         }
1568
1569         return buffer->data;
1570 }
1571
1572 EAPI int buffer_handler_raw_size(struct buffer *buffer)
1573 {
1574         if (!buffer || buffer->state != CREATED) {
1575                 return LB_STATUS_ERROR_INVALID;
1576         }
1577
1578         return (int)buffer->info;
1579 }
1580
1581 EAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
1582 {
1583         struct buffer *handle;
1584
1585         switch (buffer_type) {
1586         case BUFFER_TYPE_SHM:
1587                 handle = raw_open_shm((int)resource);
1588                 break;
1589         case BUFFER_TYPE_FILE:
1590                 handle = raw_open_file(resource);
1591                 break;
1592         case BUFFER_TYPE_PIXMAP:
1593                 handle = raw_open_pixmap((unsigned int)resource);
1594                 break;
1595         default:
1596                 handle = NULL;
1597                 break;
1598         }
1599
1600         return handle;
1601 }
1602
1603 EAPI int buffer_handler_raw_close(struct buffer *buffer)
1604 {
1605         int ret;
1606
1607         switch (buffer->type) {
1608         case BUFFER_TYPE_SHM:
1609                 ret = raw_close_shm(buffer);
1610                 break;
1611         case BUFFER_TYPE_FILE:
1612                 ret = raw_close_file(buffer);
1613                 break;
1614         case BUFFER_TYPE_PIXMAP:
1615                 ret = raw_close_pixmap(buffer);
1616                 break;
1617         default:
1618                 ret = LB_STATUS_ERROR_INVALID;
1619                 break;
1620         }
1621
1622         return ret;
1623 }
1624
1625 EAPI int buffer_handler_lock(struct buffer_info *buffer)
1626 {
1627         if (buffer->type == BUFFER_TYPE_PIXMAP) {
1628                 return LB_STATUS_SUCCESS;
1629         }
1630
1631         if (buffer->type == BUFFER_TYPE_FILE) {
1632                 return LB_STATUS_SUCCESS;
1633         }
1634
1635         return do_buffer_lock(buffer);
1636 }
1637
1638 EAPI int buffer_handler_unlock(struct buffer_info *buffer)
1639 {
1640         if (buffer->type == BUFFER_TYPE_PIXMAP) {
1641                 return LB_STATUS_SUCCESS;
1642         }
1643
1644         if (buffer->type == BUFFER_TYPE_FILE) {
1645                 return LB_STATUS_SUCCESS;
1646         }
1647
1648         return do_buffer_unlock(buffer);
1649 }
1650
1651 /*!
1652  * \note
1653  * Only can be used by master.
1654  * Plugin cannot access the user data
1655  */
1656
1657 HAPI int buffer_handler_set_data(struct buffer_info *buffer, void *data)
1658 {
1659         if (!buffer) {
1660                 ErrPrint("Invalid handle\n");
1661                 return LB_STATUS_ERROR_INVALID;
1662         }
1663
1664         buffer->data = data;
1665         return LB_STATUS_SUCCESS;
1666 }
1667
1668 HAPI void *buffer_handler_data(struct buffer_info *buffer)
1669 {
1670         if (!buffer) {
1671                 ErrPrint("Invalid handle\n");
1672                 return NULL;
1673         }
1674
1675         return buffer->data;
1676 }
1677
1678 HAPI int buffer_handler_destroy(struct buffer_info *info)
1679 {
1680         Eina_List *l;
1681         struct buffer *buffer;
1682
1683         if (!info) {
1684                 DbgPrint("Buffer is not created yet. info is NIL\n");
1685                 return LB_STATUS_SUCCESS;
1686         }
1687
1688         EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
1689                 if (buffer->info == info) {
1690                         buffer->info = NULL;
1691                 }
1692         }
1693
1694         buffer_handler_unload(info);
1695         DbgFree(info->id);
1696         DbgFree(info);
1697         return LB_STATUS_SUCCESS;
1698 }
1699
1700 HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
1701 {
1702         struct buffer_info *info;
1703
1704         info = malloc(sizeof(*info));
1705         if (!info) {
1706                 ErrPrint("Heap: %s\n", strerror(errno));
1707                 return NULL;
1708         }
1709
1710         switch (type) {
1711         case BUFFER_TYPE_SHM:
1712                 if (pixel_size != DEFAULT_PIXELS) {
1713                         DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
1714                         pixel_size = DEFAULT_PIXELS;
1715                 }
1716
1717                 info->id = strdup(SCHEMA_SHM "-1");
1718                 if (!info->id) {
1719                         ErrPrint("Heap: %s\n", strerror(errno));
1720                         DbgFree(info);
1721                         return NULL;
1722                 }
1723                 break;
1724         case BUFFER_TYPE_FILE:
1725                 if (pixel_size != DEFAULT_PIXELS) {
1726                         DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
1727                         pixel_size = DEFAULT_PIXELS;
1728                 }
1729
1730                 info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
1731                 if (!info->id) {
1732                         ErrPrint("Heap: %s\n", strerror(errno));
1733                         DbgFree(info);
1734                         return NULL;
1735                 }
1736                 break;
1737         case BUFFER_TYPE_PIXMAP:
1738                 info->id = strdup(SCHEMA_PIXMAP "0:0");
1739                 if (!info->id) {
1740                         ErrPrint("Heap: %s\n", strerror(errno));
1741                         DbgFree(info);
1742                         return NULL;
1743                 }
1744                 break;
1745         default:
1746                 ErrPrint("Invalid type\n");
1747                 DbgFree(info);
1748                 return NULL;
1749         }
1750
1751         info->lock = NULL;
1752         info->lock_fd = -1;
1753         info->w = w;
1754         info->h = h;
1755         info->pixel_size = pixel_size;
1756         info->type = type;
1757         info->is_loaded = 0;
1758         info->inst = inst;
1759         info->buffer = NULL;
1760         info->data = NULL;
1761
1762         return info;
1763 }
1764
1765 /* End of a file */