svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_x / xlib / ecore_x_image.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include "ecore_x_private.h"
10 #include "Ecore_X.h"
11
12 #include <X11/extensions/XShm.h>
13 #include <X11/Xutil.h>
14 #include <sys/ipc.h>
15 #include <sys/shm.h>
16 #include <string.h>
17
18 static int _ecore_x_image_shm_can = -1;
19 static int _ecore_x_image_err = 0;
20
21 static void
22 _ecore_x_image_error_handler(Display * d __UNUSED__, XErrorEvent * ev __UNUSED__)
23 {
24    _ecore_x_image_err = 1;
25 }
26
27 static void
28 _ecore_x_image_shm_check(void)
29 {
30    XErrorHandler ph;
31    XShmSegmentInfo shminfo;
32    XImage *xim;
33    
34    if (_ecore_x_image_shm_can != -1) return;
35    
36    XSync(_ecore_x_disp, False);
37    _ecore_x_image_err = 0;
38    
39    xim = XShmCreateImage(_ecore_x_disp, 
40                          DefaultVisual(_ecore_x_disp, 
41                                        DefaultScreen(_ecore_x_disp)), 
42                          DefaultDepth(_ecore_x_disp, 
43                                       DefaultScreen(_ecore_x_disp)),
44                          ZPixmap, NULL, 
45                          &shminfo, 1, 1);
46    if (!xim)
47      {
48         _ecore_x_image_shm_can = 0;
49         return;
50      }
51
52    shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height,
53                           IPC_CREAT | 0666);
54    if (shminfo.shmid == -1)
55      {
56         XDestroyImage(xim);
57         _ecore_x_image_shm_can = 0;
58         return;
59      }
60    
61    shminfo.readOnly = False;
62    shminfo.shmaddr  = shmat(shminfo.shmid, 0, 0);
63    xim->data = shminfo.shmaddr;
64    
65    if (xim->data == (char *)-1)
66      {
67         XDestroyImage(xim);
68         _ecore_x_image_shm_can = 0;
69         return;
70      }
71    
72    ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
73    XShmAttach(_ecore_x_disp, &shminfo);
74    XShmGetImage(_ecore_x_disp, DefaultRootWindow(_ecore_x_disp), 
75                 xim, 0, 0, 0xffffffff);
76    XSync(_ecore_x_disp, False);
77    XSetErrorHandler((XErrorHandler)ph);
78    if (_ecore_x_image_err)
79      {
80         XShmDetach(_ecore_x_disp, &shminfo);
81         XDestroyImage(xim);
82         shmdt(shminfo.shmaddr); 
83         shmctl(shminfo.shmid, IPC_RMID, 0);
84         _ecore_x_image_shm_can = 0;
85         return;
86      }
87    
88    XShmDetach(_ecore_x_disp, &shminfo);
89    XDestroyImage(xim);
90    shmdt(shminfo.shmaddr);
91    shmctl(shminfo.shmid, IPC_RMID, 0);
92    
93    _ecore_x_image_shm_can = 1;
94 }
95
96 struct _Ecore_X_Image
97 {
98    XShmSegmentInfo shminfo;
99    Ecore_X_Visual vis;
100    XImage *xim;
101    int depth;
102    int w, h;
103    int bpl, bpp, rows;
104    unsigned char *data;
105    Eina_Bool shm : 1;
106 };
107
108 EAPI Ecore_X_Image *
109 ecore_x_image_new(int w, int h, Ecore_X_Visual vis, int depth)
110 {
111    Ecore_X_Image *im;
112    
113    im = calloc(1, sizeof(Ecore_X_Image));
114    if (!im) return NULL;
115    LOGFN(__FILE__, __LINE__, __FUNCTION__);
116    im->w = w;
117    im->h = h;
118    im->vis = vis;
119    im->depth = depth;
120    _ecore_x_image_shm_check();
121    im->shm = _ecore_x_image_shm_can;
122    return im;
123 }
124
125 EAPI void
126 ecore_x_image_free(Ecore_X_Image *im)
127 {
128    LOGFN(__FILE__, __LINE__, __FUNCTION__);
129    if (im->shm)
130      {
131         if (im->xim)
132           {
133              XShmDetach(_ecore_x_disp, &(im->shminfo));
134              XDestroyImage(im->xim);
135              shmdt(im->shminfo.shmaddr);
136              shmctl(im->shminfo.shmid, IPC_RMID, 0);
137           }
138      }
139    else
140      {
141         if (im->xim)
142           {
143              free(im->xim->data);
144              im->xim->data = NULL;
145              XDestroyImage(im->xim);
146           }
147      }
148    free(im);
149 }
150
151 static void
152 _ecore_x_image_shm_create(Ecore_X_Image *im)
153 {
154    im->xim = XShmCreateImage(_ecore_x_disp, im->vis, im->depth,
155                              ZPixmap, NULL, &(im->shminfo), 
156                              im->w, im->h);
157    if (!im->xim) return;
158
159    im->shminfo.shmid = shmget(IPC_PRIVATE, 
160                               im->xim->bytes_per_line * im->xim->height,
161                               IPC_CREAT | 0666);
162    if (im->shminfo.shmid == -1)
163      {
164         XDestroyImage(im->xim);
165         return;
166      }
167    im->shminfo.readOnly = False;
168    im->shminfo.shmaddr  = shmat(im->shminfo.shmid, 0, 0);
169    im->xim->data = im->shminfo.shmaddr;
170    if ((im->xim->data == (char *)-1) ||
171        (im->xim->data == NULL))
172      {
173         shmdt(im->shminfo.shmaddr);
174         shmctl(im->shminfo.shmid, IPC_RMID, 0);
175         XDestroyImage(im->xim);
176         return;
177      } 
178    XShmAttach(_ecore_x_disp, &im->shminfo);
179    
180    im->data = (unsigned char *)im->xim->data;
181
182    im->bpl = im->xim->bytes_per_line;
183    im->rows = im->xim->height;
184    if (im->xim->bits_per_pixel <= 8) im->bpp = 1;
185    else if (im->xim->bits_per_pixel <= 16) im->bpp = 2;
186    else im->bpp = 4;
187 }
188
189 EAPI Eina_Bool
190 ecore_x_image_get(Ecore_X_Image *im, Ecore_X_Drawable draw, 
191                   int x, int y, int sx, int sy, int w, int h)
192 {
193    int ret = 1;
194    XErrorHandler ph;
195    
196    LOGFN(__FILE__, __LINE__, __FUNCTION__);
197    if (im->shm)
198      {
199         if (!im->xim) _ecore_x_image_shm_create(im);
200         if (!im->xim) return 0;
201         _ecore_x_image_err = 0;
202         // optimised path
203         ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
204         if ((sx == 0) && (w == im->w))
205           {
206              im->xim->data = (char *)
207                im->data + (im->xim->bytes_per_line * sy) + (sx * im->bpp);
208              im->xim->width = w;
209              im->xim->height = h;
210              if (!XShmGetImage(_ecore_x_disp, draw, im->xim, x, y, 0xffffffff))
211                ret = 0;
212              ecore_x_sync();
213           }
214         // unavoidable thanks to mit-shm get api - tmp shm buf + copy into it
215         else
216           {
217              Ecore_X_Image *tim;
218              unsigned char *spixels, *sp, *pixels, *p;
219              int bpp, bpl, rows, sbpp, sbpl, srows;
220              int r;
221              
222              tim = ecore_x_image_new(w, h, im->vis, im->depth);
223              if (tim)
224                {
225                   ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h);
226                   if (ret)
227                     {
228                        spixels = ecore_x_image_data_get(tim, &sbpl, &srows, &sbpp);
229                        pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp);
230                        if ((pixels) && (spixels))
231                          {
232                             p = pixels + (sy * bpl) + (sx * bpp);
233                             sp = spixels;
234                             for (r = srows; r > 0; r--)
235                               {
236                                  memcpy(p, sp, sbpl);
237                                  p += bpl;
238                                  sp += sbpl;
239                               }
240                          }
241                     }
242                   ecore_x_image_free(tim);
243                }
244           }
245         XSetErrorHandler((XErrorHandler)ph);
246         if (_ecore_x_image_err) ret = 0;
247      }
248    else
249      {
250         printf("currently unimplemented ecore_x_image_get without shm\n");
251         ret = 0;
252      }
253    return ret;
254 }
255
256 EAPI void
257 ecore_x_image_put(Ecore_X_Image *im __UNUSED__, Ecore_X_Drawable draw __UNUSED__, int x __UNUSED__, int y __UNUSED__, int sx __UNUSED__, int sy __UNUSED__, int w __UNUSED__, int h __UNUSED__)
258 {
259    LOGFN(__FILE__, __LINE__, __FUNCTION__);
260    printf("ecore_x_image_put: unimplemented!\n");
261 }
262
263 EAPI void *
264 ecore_x_image_data_get(Ecore_X_Image *im, int *bpl, int *rows, int *bpp)
265 {
266    LOGFN(__FILE__, __LINE__, __FUNCTION__);
267    if (!im->xim) _ecore_x_image_shm_create(im);
268    if (!im->xim) return NULL;
269    
270    if (bpl) *bpl = im->bpl;
271    if (rows) *rows = im->rows;
272    if (bpp) *bpp = im->bpp;
273    return im->data;
274 }