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