Ecore_X(cb): Remove extra calls to ecore_x_flush. Move main loop
[framework/uifw/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb_image.c
1 #include "ecore_xcb_private.h"
2 #include <sys/ipc.h>
3 #include <sys/shm.h>
4 #include <xcb/xcb_event.h>
5 #include <xcb/shm.h>
6
7 struct _Ecore_X_Image 
8 {
9    xcb_shm_segment_info_t shminfo;
10    xcb_image_t *xim;
11    Ecore_X_Visual vis;
12    int depth, w, h;
13    int bpl, bpp, rows;
14    unsigned char *data;
15    Eina_Bool shm : 1;
16 };
17
18 /* local function prototypes */
19 static void _ecore_xcb_image_shm_check(void);
20 static void _ecore_xcb_image_shm_create(Ecore_X_Image *im);
21 static xcb_format_t *_ecore_xcb_image_find_format(const xcb_setup_t *setup, uint8_t depth);
22
23 /* local variables */
24 static int _ecore_xcb_image_shm_can = -1;
25
26 EAPI Ecore_X_Image *
27 ecore_x_image_new(int w, int h, Ecore_X_Visual vis, int depth) 
28 {
29    Ecore_X_Image *im;
30
31    LOGFN(__FILE__, __LINE__, __FUNCTION__);
32
33    if (!(im = calloc(1, sizeof(Ecore_X_Image)))) return NULL;
34    im->w = w;
35    im->h = h;
36    im->vis = vis;
37    im->depth = depth;
38    _ecore_xcb_image_shm_check();
39    im->shm = _ecore_xcb_image_shm_can;
40    return im;
41 }
42
43 EAPI void 
44 ecore_x_image_free(Ecore_X_Image *im) 
45 {
46    LOGFN(__FILE__, __LINE__, __FUNCTION__);
47
48    if (!im) return;
49    if (im->shm) 
50      {
51         if (im->xim) 
52           {
53              xcb_shm_detach(_ecore_xcb_conn, im->shminfo.shmseg);
54              xcb_image_destroy(im->xim);
55              shmdt(im->shminfo.shmaddr);
56              shmctl(im->shminfo.shmid, IPC_RMID, 0);
57           }
58      }
59    else if (im->xim) 
60      {
61         if (im->xim->data) free(im->xim->data);
62         im->xim->data = NULL;
63         xcb_image_destroy(im->xim);
64      }
65
66    free(im);
67 //   ecore_x_flush();
68 }
69
70 EAPI Eina_Bool 
71 ecore_x_image_get(Ecore_X_Image *im, Ecore_X_Drawable draw, int x, int y, int sx, int sy, int w, int h) 
72 {
73    Eina_Bool ret = EINA_TRUE;
74
75    LOGFN(__FILE__, __LINE__, __FUNCTION__);
76
77    if (im->shm) 
78      {
79         if (!im->xim) _ecore_xcb_image_shm_create(im);
80         if (!im->xim) return EINA_FALSE;
81
82         if ((sx == 0) && (w == im->w)) 
83           {
84              im->xim->data = (uint8_t *)im->data + (im->xim->stride * sy) + 
85                (sx * im->bpp);
86              im->xim->width = w;
87              im->xim->height = h;
88
89              ecore_x_grab();
90              if (!xcb_image_shm_get(_ecore_xcb_conn, draw, im->xim, 
91                                     im->shminfo, x, y, 0xffffffff)) 
92                {
93                   DBG("\tImage Shm Get Failed");
94                   ret = EINA_FALSE;
95                }
96              ecore_x_ungrab();
97              ecore_x_sync(); // needed
98           }
99         else 
100           {
101              Ecore_X_Image *tim;
102
103              tim = ecore_x_image_new(w, h, im->vis, im->depth);
104              if (tim) 
105                {
106                   ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h);
107                   if (ret) 
108                     {
109                        unsigned char *spixels, *pixels;
110                        int sbpp = 0, sbpl = 0, srows = 0;
111                        int bpp = 0, bpl = 0, rows = 0;
112
113                        spixels = 
114                          ecore_x_image_data_get(tim, &sbpl, &srows, &sbpp);
115                        pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp);
116                        if ((spixels) && (pixels)) 
117                          {
118                             unsigned char *p, *sp;
119                             int r = 0;
120
121                             p = (pixels + (sy * bpl) + (sx * bpp));
122                             sp = spixels;
123                             for (r = srows; r > 0; r--) 
124                               {
125                                  memcpy(p, sp, sbpl);
126                                  p += bpl;
127                                  sp += sbpl;
128                               }
129                          }
130                     }
131                   ecore_x_image_free(tim);
132                }
133           }
134      }
135    else 
136      {
137         ret = EINA_FALSE;
138         ecore_x_grab();
139         im->xim = 
140           xcb_image_get(_ecore_xcb_conn, draw, x, y, w, h, 
141                         0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
142         if (!im->xim) ret = EINA_FALSE;
143         ecore_x_ungrab();
144         ecore_x_sync(); // needed
145
146         if (im->xim) 
147           {
148              im->data = (unsigned char *)im->xim->data;
149              im->bpl = im->xim->stride;
150              im->rows = im->xim->height;
151              if (im->xim->bpp <= 8)
152                im->bpp = 1;
153              else if (im->xim->bpp <= 16)
154                im->bpp = 2;
155              else
156                im->bpp = 4;
157           }
158      }
159
160    return ret;
161 }
162
163 EAPI void *
164 ecore_x_image_data_get(Ecore_X_Image *im, int *bpl, int *rows, int *bpp) 
165 {
166    LOGFN(__FILE__, __LINE__, __FUNCTION__);
167
168    if (!im) return NULL;
169    if (!im->xim) _ecore_xcb_image_shm_create(im);
170    if (!im->xim) return NULL;
171
172    if (bpl) *bpl = im->bpl;
173    if (rows) *rows = im->rows;
174    if (bpp) *bpp = im->bpp;
175
176    return im->data;
177 }
178
179 EAPI void 
180 ecore_x_image_put(Ecore_X_Image *im, Ecore_X_Drawable draw, Ecore_X_GC gc, int x, int y, int sx, int sy, int w, int h) 
181 {
182    Ecore_X_GC tgc = 0;
183
184    LOGFN(__FILE__, __LINE__, __FUNCTION__);
185
186    if (!gc) 
187      {
188         uint32_t mask, values[1];
189
190         tgc = xcb_generate_id(_ecore_xcb_conn);
191         mask = XCB_GC_SUBWINDOW_MODE;
192         values[0] = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
193         xcb_create_gc(_ecore_xcb_conn, tgc, draw, mask, values);
194         gc = tgc;
195      }
196    if (!im->xim) _ecore_xcb_image_shm_create(im);
197    if (im->xim) 
198      {
199         if (im->shm) 
200           xcb_shm_put_image(_ecore_xcb_conn, draw, gc, im->xim->width, 
201                             im->xim->height, sx, sy, w, h, x, y, 
202                             im->xim->depth, im->xim->format, 0, 
203                             im->shminfo.shmseg, 
204                             im->xim->data - im->shminfo.shmaddr);
205 //          xcb_image_shm_put(_ecore_xcb_conn, draw, gc, im->xim, 
206 //                            im->shminfo, sx, sy, x, y, w, h, 0);
207         else 
208           xcb_image_put(_ecore_xcb_conn, draw, gc, im->xim, sx, sy, 0);
209
210      }
211    if (tgc) ecore_x_gc_free(tgc);
212    ecore_x_sync();
213 }
214
215 EAPI Eina_Bool 
216 ecore_x_image_is_argb32_get(Ecore_X_Image *im) 
217 {
218    xcb_visualtype_t *vis;
219
220    LOGFN(__FILE__, __LINE__, __FUNCTION__);
221
222    vis = (xcb_visualtype_t *)im->vis;
223    if (!im->xim) _ecore_xcb_image_shm_create(im);
224
225    if (((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) || 
226         (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR)) && 
227        (im->depth >= 24) && (vis->red_mask == 0xff0000) && 
228        (vis->green_mask == 0x00ff00) && (vis->blue_mask == 0x0000ff))
229      {
230 #ifdef WORDS_BIGENDIAN
231         if (im->xim->byte_order == XCB_IMAGE_ORDER_LSB_FIRST) 
232           return EINA_TRUE;
233 #else
234         if (im->xim->byte_order == XCB_IMAGE_ORDER_MSB_FIRST) 
235           return EINA_TRUE;
236 #endif
237      }
238
239    return EINA_FALSE;
240 }
241
242 EAPI Eina_Bool 
243 ecore_x_image_to_argb_convert(void *src, int sbpp, int sbpl, Ecore_X_Colormap c, Ecore_X_Visual v, int x, int y, int w, int h, unsigned int *dst, int dbpl, int dx, int dy) 
244 {
245    xcb_visualtype_t *vis;
246    uint32_t *cols;
247    int n = 0, nret = 0, i, row, mode = 0;
248    unsigned int pal[256], r, g, b;
249    enum
250      {
251         rgbnone = 0,
252         rgb565,
253         bgr565,
254         rgbx555,
255         argbx888,
256         abgrx888,
257         rgba888x,
258         bgra888x,
259         argbx666
260      };
261
262    LOGFN(__FILE__, __LINE__, __FUNCTION__);
263
264    sbpp *= 8;
265
266    vis = (xcb_visualtype_t *)v;
267    n = vis->colormap_entries;
268    if ((n <= 256) &&
269        ((vis->_class == XCB_VISUAL_CLASS_PSEUDO_COLOR) ||
270            (vis->_class == XCB_VISUAL_CLASS_STATIC_COLOR) ||
271            (vis->_class == XCB_VISUAL_CLASS_GRAY_SCALE) ||
272            (vis->_class == XCB_VISUAL_CLASS_STATIC_GRAY)))
273      {
274         xcb_query_colors_cookie_t cookie;
275         xcb_query_colors_reply_t *reply;
276
277         if (!c) 
278           {
279              c = (xcb_colormap_t)((xcb_screen_t *)
280                                   _ecore_xcb_screen)->default_colormap;
281           }
282
283         cols = alloca(n * sizeof(uint32_t));
284         for (i = 0; i < n; i++)
285           cols[i] = i;
286
287         cookie = xcb_query_colors_unchecked(_ecore_xcb_conn, c, n, cols);
288         reply = xcb_query_colors_reply(_ecore_xcb_conn, cookie, NULL);
289         if (reply) 
290           {
291              xcb_rgb_iterator_t iter;
292              xcb_rgb_t *ret;
293
294              iter = xcb_query_colors_colors_iterator(reply);
295              ret = xcb_query_colors_colors(reply);
296              if (ret) 
297                {
298                   for (i = 0; iter.rem; xcb_rgb_next(&iter), i++) 
299                     {
300                        pal[i] = 0xff000000 | 
301                          ((iter.data->red   >> 8) << 16) |
302                          ((iter.data->green >> 8) << 8) |
303                          ((iter.data->blue  >> 8));
304                     }
305                   nret = n;
306                }
307              free(reply);
308           }
309      }
310    else if ((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) || 
311             (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR))
312      {
313         if ((vis->red_mask   == 0x00ff0000) &&
314             (vis->green_mask == 0x0000ff00) &&
315             (vis->blue_mask  == 0x000000ff))
316           mode = argbx888;
317         else if ((vis->red_mask   == 0x000000ff) &&
318                  (vis->green_mask == 0x0000ff00) &&
319                  (vis->blue_mask  == 0x00ff0000))
320           mode = abgrx888;
321         else if ((vis->red_mask   == 0xff000000) &&
322                  (vis->green_mask == 0x00ff0000) &&
323                  (vis->blue_mask  == 0x0000ff00))
324           mode = rgba888x;
325         else if ((vis->red_mask   == 0x0000ff00) &&
326                  (vis->green_mask == 0x00ff0000) &&
327                  (vis->blue_mask  == 0xff000000))
328           mode = bgra888x;
329         else if ((vis->red_mask   == 0x0003f000) &&
330                  (vis->green_mask == 0x00000fc0) &&
331                  (vis->blue_mask  == 0x0000003f))
332           mode = argbx666;
333         else if ((vis->red_mask   == 0x0000f800) &&
334                  (vis->green_mask == 0x000007e0) &&
335                  (vis->blue_mask  == 0x0000001f))
336           mode = rgb565;
337         else if ((vis->red_mask   == 0x0000001f) &&
338                  (vis->green_mask == 0x000007e0) &&
339                  (vis->blue_mask  == 0x0000f800))
340           mode = bgr565;
341         else if ((vis->red_mask   == 0x00007c00) &&
342                  (vis->green_mask == 0x000003e0) &&
343                  (vis->blue_mask  == 0x0000001f))
344           mode = rgbx555;
345         else
346           return EINA_FALSE;
347      }
348    for (row = 0; row < h; row++)
349      {
350         unsigned char *s8;
351         unsigned short *s16;
352         unsigned int *s32, *dp, *de;
353
354         dp = ((unsigned int *)(((unsigned char *)dst) + 
355                                ((dy + row) * dbpl))) + dx;
356         de = dp + w;
357         switch (sbpp)
358           {
359            case 8:
360              s8 = ((unsigned char *)(((unsigned char *)src) + 
361                                      ((y + row) * sbpl))) + x;
362              if (nret > 0)
363                {
364                   while (dp < de)
365                     {
366                        *dp = pal[*s8];
367                        s8++; dp++;
368                     }
369                }
370              else
371                return EINA_FALSE;
372              break;
373            case 16:
374              s16 = ((unsigned short *)(((unsigned char *)src) + 
375                                        ((y + row) * sbpl))) + x;
376              switch (mode)
377                {
378                 case rgb565:
379                   while (dp < de)
380                     {
381                        r = (*s16 & 0xf800) << 8;
382                        g = (*s16 & 0x07e0) << 5;
383                        b = (*s16 & 0x001f) << 3;
384                        r |= (r >> 5) & 0xff0000;
385                        g |= (g >> 6) & 0x00ff00;
386                        b |= (b >> 5);
387                        *dp = 0xff000000 | r | g | b;
388                        s16++; dp++;
389                     }
390                   break;
391                 case bgr565:
392                   while (dp < de)
393                     {
394                        r = (*s16 & 0x001f) << 19;
395                        g = (*s16 & 0x07e0) << 5;
396                        b = (*s16 & 0xf800) >> 8;
397                        r |= (r >> 5) & 0xff0000;
398                        g |= (g >> 6) & 0x00ff00;
399                        b |= (b >> 5);
400                        *dp = 0xff000000 | r | g | b;
401                        s16++; dp++;
402                     }
403                   break;
404                 case rgbx555:
405                   while (dp < de)
406                     {
407                        r = (*s16 & 0x7c00) << 9;
408                        g = (*s16 & 0x03e0) << 6;
409                        b = (*s16 & 0x001f) << 3;
410                        r |= (r >> 5) & 0xff0000;
411                        g |= (g >> 5) & 0x00ff00;
412                        b |= (b >> 5);
413                        *dp = 0xff000000 | r | g | b;
414                        s16++; dp++;
415                     }
416                   break;
417                 default:
418                   return EINA_FALSE;
419                   break;
420                }
421              break;
422            case 24:
423            case 32:
424              s32 = ((unsigned int *)(((unsigned char *)src) + 
425                                      ((y + row) * sbpl))) + x;
426              switch (mode)
427                {
428                 case argbx888:
429                   while (dp < de)
430                     {
431                        *dp = 0xff000000 | *s32;
432                        s32++; dp++;
433                     }
434                   break;
435                 case abgrx888:
436                   while (dp < de)
437                     {
438                        r = *s32 & 0x000000ff;
439                        g = *s32 & 0x0000ff00;
440                        b = *s32 & 0x00ff0000;
441                        *dp = 0xff000000 | (r << 16) | (g) | (b >> 16);
442                        s32++; dp++;
443                     }
444                   break;
445                 case rgba888x:
446                   while (dp < de)
447                     {
448                        *dp = 0xff000000 | (*s32 >> 8);
449                        s32++; dp++;
450                     }
451                   break;
452                 case bgra888x:
453                   while (dp < de)
454                     {
455                        r = *s32 & 0x0000ff00;
456                        g = *s32 & 0x00ff0000;
457                        b = *s32 & 0xff000000;
458                        *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24);
459                        s32++; dp++;
460                     }
461                   break;
462                 case argbx666:
463                   while (dp < de)
464                     {
465                        r = (*s32 & 0x3f000) << 6;
466                        g = (*s32 & 0x00fc0) << 4;
467                        b = (*s32 & 0x0003f) << 2;
468                        r |= (r >> 6) & 0xff0000;
469                        g |= (g >> 6) & 0x00ff00;
470                        b |= (b >> 6);
471                        *dp = 0xff000000 | r | g | b;
472                        s32++; dp++;
473                     }
474                   break;
475                 default:
476                   return EINA_FALSE;
477                   break;
478                }
479              break;
480              break;
481            default:
482              return EINA_FALSE;
483              break;
484           }
485      }
486    return EINA_TRUE;
487 }
488
489 /* local functions */
490 static void 
491 _ecore_xcb_image_shm_check(void) 
492 {
493 //   xcb_shm_query_version_reply_t *reply;
494    xcb_shm_segment_info_t shminfo;
495    xcb_shm_get_image_cookie_t cookie;
496    xcb_shm_get_image_reply_t *ireply;
497    xcb_image_t *img = 0;
498    uint8_t depth = 0;
499
500    if (_ecore_xcb_image_shm_can != -1) return;
501
502    /* reply =  */
503    /*   xcb_shm_query_version_reply(_ecore_xcb_conn,  */
504    /*                               xcb_shm_query_version(_ecore_xcb_conn), NULL); */
505    /* if (!reply)  */
506    /*   { */
507    /*      _ecore_xcb_image_shm_can = 0; */
508    /*      return; */
509    /*   } */
510
511    /* if ((reply->major_version < 1) ||  */
512    /*     ((reply->major_version == 1) && (reply->minor_version == 0)))  */
513    /*   { */
514    /*      _ecore_xcb_image_shm_can = 0; */
515    /*      free(reply); */
516    /*      return; */
517    /*   } */
518
519    /* free(reply); */
520
521    depth = ((xcb_screen_t *)_ecore_xcb_screen)->root_depth;
522
523    ecore_x_sync(); // needed
524
525    img = _ecore_xcb_image_create_native(1, 1, XCB_IMAGE_FORMAT_Z_PIXMAP, 
526                                         depth, NULL, ~0, NULL);
527    if (!img) 
528      {
529         _ecore_xcb_image_shm_can = 0;
530         return;
531      }
532
533    shminfo.shmid = 
534      shmget(IPC_PRIVATE, img->stride * img->height, (IPC_CREAT | 0666));
535    if (shminfo.shmid == (uint32_t)-1) 
536      {
537         xcb_image_destroy(img);
538         _ecore_xcb_image_shm_can = 0;
539         return;
540      }
541
542    shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
543    img->data = shminfo.shmaddr;
544    if (img->data == (uint8_t *)-1) 
545      {
546         xcb_image_destroy(img);
547         _ecore_xcb_image_shm_can = 0;
548         return;
549      }
550
551    shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn);
552    xcb_shm_attach(_ecore_xcb_conn, shminfo.shmseg, shminfo.shmid, 0);
553
554    cookie = 
555      xcb_shm_get_image(_ecore_xcb_conn, 
556                        ((xcb_screen_t *)_ecore_xcb_screen)->root, 
557                        0, 0, img->width, img->height, 
558                        0xffffffff, img->format, 
559                        shminfo.shmseg, img->data - shminfo.shmaddr);
560
561    ecore_x_sync(); // needed
562
563    ireply = xcb_shm_get_image_reply(_ecore_xcb_conn, cookie, NULL);
564    if (ireply) 
565      {
566         _ecore_xcb_image_shm_can = 1;
567         free(ireply);
568      }
569    else
570      _ecore_xcb_image_shm_can = 0;
571
572    xcb_shm_detach(_ecore_xcb_conn, shminfo.shmseg);
573    xcb_image_destroy(img);
574    shmdt(shminfo.shmaddr);
575    shmctl(shminfo.shmid, IPC_RMID, 0);
576 }
577
578 static void 
579 _ecore_xcb_image_shm_create(Ecore_X_Image *im) 
580 {
581    im->xim = 
582      _ecore_xcb_image_create_native(im->w, im->h, XCB_IMAGE_FORMAT_Z_PIXMAP, 
583                                     im->depth, NULL, ~0, NULL);
584    if (!im->xim) return;
585
586    im->shminfo.shmid = shmget(IPC_PRIVATE, im->xim->size, (IPC_CREAT | 0666));
587    if (im->shminfo.shmid == (uint32_t)-1) 
588      {
589         xcb_image_destroy(im->xim);
590         return;
591      }
592
593    im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0);
594    im->xim->data = im->shminfo.shmaddr;
595    if ((!im->xim->data) || (im->xim->data == (uint8_t *)-1))
596      {
597         DBG("Shm Create No Image Data");
598         xcb_image_destroy(im->xim);
599         shmdt(im->shminfo.shmaddr);
600         shmctl(im->shminfo.shmid, IPC_RMID, 0);
601         return;
602      }
603
604    im->shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn);
605    xcb_shm_attach(_ecore_xcb_conn, im->shminfo.shmseg, im->shminfo.shmid, 0);
606
607    im->data = (unsigned char *)im->xim->data;
608    im->bpl = im->xim->stride;
609    im->rows = im->xim->height;
610    if (im->xim->bpp <= 8)
611      im->bpp = 1;
612    else if (im->xim->bpp <= 16)
613      im->bpp = 2;
614    else
615      im->bpp = 4;
616 }
617
618 xcb_image_t *
619 _ecore_xcb_image_create_native(int w, int h, xcb_image_format_t format, uint8_t depth, void *base, uint32_t bytes, uint8_t *data) 
620 {
621    static uint8_t dpth = 0;
622    static xcb_format_t *fmt = NULL;
623    const xcb_setup_t *setup;
624    xcb_image_format_t xif;
625
626    /* NB: We cannot use xcb_image_create_native as it only creates images 
627     * using MSB_FIRST, so this routine recreates that function and uses 
628     * the endian-ness of the server setup */
629    setup = xcb_get_setup(_ecore_xcb_conn);
630    xif = format;
631
632    if ((xif == XCB_IMAGE_FORMAT_Z_PIXMAP) && (depth == 1))
633      xif = XCB_IMAGE_FORMAT_XY_PIXMAP;
634
635    if (dpth != depth) 
636      {
637         dpth = depth;
638         fmt = _ecore_xcb_image_find_format(setup, depth);
639         if (!fmt) return 0;
640      }
641
642    switch (xif) 
643      {
644       case XCB_IMAGE_FORMAT_XY_BITMAP:
645         if (depth != 1) return 0;
646       case XCB_IMAGE_FORMAT_XY_PIXMAP:
647       case XCB_IMAGE_FORMAT_Z_PIXMAP:
648         return xcb_image_create(w, h, xif, 
649                                 fmt->scanline_pad, 
650                                 fmt->depth, fmt->bits_per_pixel, 
651                                 setup->bitmap_format_scanline_unit, 
652                                 setup->image_byte_order, 
653                                 setup->bitmap_format_bit_order, 
654                                 base, bytes, data);
655       default:
656         break;
657      }
658
659    return 0;
660 }
661
662 static xcb_format_t *
663 _ecore_xcb_image_find_format(const xcb_setup_t *setup, uint8_t depth) 
664 {
665    xcb_format_t *fmt, *fmtend;
666
667    fmt = xcb_setup_pixmap_formats(setup);
668    fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
669    for (; fmt != fmtend; ++fmt)
670      if (fmt->depth == depth) 
671        return fmt;
672
673    return 0;
674 }