Evas: Remove dependency on xcb-aux and add code to find the visual
[framework/uifw/evas.git] / src / modules / engines / software_x11 / evas_xcb_buffer.c
1 #include "evas_common.h"
2 #include "evas_xcb_buffer.h"
3
4 /* local function prototypes */
5 static void _xcbob_sync(xcb_connection_t *conn);
6 static xcb_image_t *_xcbob_create_native(xcb_connection_t *conn, int w, int h, xcb_image_format_t format, uint8_t depth, void *base, uint32_t bytes, uint8_t *data);
7 static xcb_format_t *_xcbob_find_format(const xcb_setup_t *setup, uint8_t depth);
8 static xcb_visualtype_t *_xcbob_find_visual_by_id(xcb_screen_t *screen, xcb_visualid_t id);
9
10 void 
11 evas_software_xcb_write_mask_line(Outbuf *buf, Xcb_Output_Buffer *xcbob, DATA32 *src, int w, int y) 
12 {
13    int x, bpl = 0;
14    DATA32 *src_ptr;
15    DATA8 *dst_ptr;
16
17    src_ptr = src;
18    dst_ptr = evas_software_xcb_output_buffer_data(xcbob, &bpl);
19    dst_ptr = dst_ptr + (bpl * y);
20    w -= 7;
21    if (buf->priv.x11.xcb.bit_swap)
22      {
23         for (x = 0; x < w; x += 8)
24           {
25              *dst_ptr =
26                ((A_VAL(&(src_ptr[0])) >> 7) << 7) |
27                ((A_VAL(&(src_ptr[1])) >> 7) << 6) |
28                ((A_VAL(&(src_ptr[2])) >> 7) << 5) |
29                ((A_VAL(&(src_ptr[3])) >> 7) << 4) |
30                ((A_VAL(&(src_ptr[4])) >> 7) << 3) |
31                ((A_VAL(&(src_ptr[5])) >> 7) << 2) |
32                ((A_VAL(&(src_ptr[6])) >> 7) << 1) |
33                ((A_VAL(&(src_ptr[7])) >> 7) << 0);
34              src_ptr += 8;
35              dst_ptr++;
36           }
37      }
38    else
39      {
40         for (x = 0; x < w; x += 8)
41           {
42              *dst_ptr =
43                ((A_VAL(&(src_ptr[0])) >> 7) << 0) |
44                ((A_VAL(&(src_ptr[1])) >> 7) << 1) |
45                ((A_VAL(&(src_ptr[2])) >> 7) << 2) |
46                ((A_VAL(&(src_ptr[3])) >> 7) << 3) |
47                ((A_VAL(&(src_ptr[4])) >> 7) << 4) |
48                ((A_VAL(&(src_ptr[5])) >> 7) << 5) |
49                ((A_VAL(&(src_ptr[6])) >> 7) << 6) |
50                ((A_VAL(&(src_ptr[7])) >> 7) << 7);
51              src_ptr += 8;
52              dst_ptr++;
53           }
54      }
55    w += 7;
56    for (; x < w; x ++)
57      {
58         xcb_image_put_pixel(xcbob->xim, x, y, A_VAL(src_ptr) >> 7);
59         src_ptr++;
60      }
61 }
62
63 void 
64 evas_software_xcb_write_mask_line_rev(Outbuf *buf, Xcb_Output_Buffer *xcbob, DATA32 *src, int w, int y) 
65 {
66    int x, bpl = 0;
67    DATA32 *src_ptr;
68    DATA8 *dst_ptr;
69
70    src_ptr = src + w - 1;
71    dst_ptr = evas_software_xcb_output_buffer_data(xcbob, &bpl);
72    dst_ptr = dst_ptr + (bpl * y);
73    w -= 7;
74    if (buf->priv.x11.xcb.bit_swap)
75      {
76         for (x = 0; x < w; x += 8)
77           {
78              *dst_ptr =
79                ((A_VAL(&(src_ptr[ 0])) >> 7) << 7) |
80                ((A_VAL(&(src_ptr[-1])) >> 7) << 6) |
81                ((A_VAL(&(src_ptr[-2])) >> 7) << 5) |
82                ((A_VAL(&(src_ptr[-3])) >> 7) << 4) |
83                ((A_VAL(&(src_ptr[-4])) >> 7) << 3) |
84                ((A_VAL(&(src_ptr[-5])) >> 7) << 2) |
85                ((A_VAL(&(src_ptr[-6])) >> 7) << 1) |
86                ((A_VAL(&(src_ptr[-7])) >> 7) << 0);
87              src_ptr -= 8;
88              dst_ptr++;
89           }
90      }
91    else
92      {
93         for (x = 0; x < w; x += 8)
94           {
95              *dst_ptr =
96                ((A_VAL(&(src_ptr[ 0])) >> 7) << 0) |
97                ((A_VAL(&(src_ptr[-1])) >> 7) << 1) |
98                ((A_VAL(&(src_ptr[-2])) >> 7) << 2) |
99                ((A_VAL(&(src_ptr[-3])) >> 7) << 3) |
100                ((A_VAL(&(src_ptr[-4])) >> 7) << 4) |
101                ((A_VAL(&(src_ptr[-5])) >> 7) << 5) |
102                ((A_VAL(&(src_ptr[-6])) >> 7) << 6) |
103                ((A_VAL(&(src_ptr[-7])) >> 7) << 7);
104              src_ptr -= 8;
105              dst_ptr++;
106           }
107      }
108    w += 7;
109    for (; x < w; x ++)
110      {
111         xcb_image_put_pixel(xcbob->xim, x, y, A_VAL(src_ptr) >> 7);
112         src_ptr--;
113      }
114 }
115
116 void 
117 evas_software_xcb_write_mask_line_vert(Outbuf *buf, Xcb_Output_Buffer *xcbob, DATA32 *src, int h, int y, int w) 
118 {
119    int yy, bpl = 0;
120    DATA32 *src_ptr;
121    DATA8 *dst_ptr;
122
123    src_ptr = src;
124    dst_ptr = evas_software_xcb_output_buffer_data(xcbob, &bpl);
125    dst_ptr = dst_ptr + (bpl * y);
126    h -= 7;
127    if (buf->priv.x11.xcb.bit_swap)
128      {
129         for (yy = 0; yy < h; yy += 8)
130           {
131              *dst_ptr =
132                ((A_VAL(&(src_ptr[0 * w])) >> 7) << 7) |
133                ((A_VAL(&(src_ptr[1 * w])) >> 7) << 6) |
134                ((A_VAL(&(src_ptr[2 * w])) >> 7) << 5) |
135                ((A_VAL(&(src_ptr[3 * w])) >> 7) << 4) |
136                ((A_VAL(&(src_ptr[4 * w])) >> 7) << 3) |
137                ((A_VAL(&(src_ptr[5 * w])) >> 7) << 2) |
138                ((A_VAL(&(src_ptr[6 * w])) >> 7) << 1) |
139                ((A_VAL(&(src_ptr[7 * w])) >> 7) << 0);
140              src_ptr += 8 * w;
141              dst_ptr++;
142           }
143      }
144    else
145      {
146         for (yy = 0; yy < h; yy += 8)
147           {
148              *dst_ptr =
149                ((A_VAL(&(src_ptr[0 * w])) >> 7) << 0) |
150                ((A_VAL(&(src_ptr[1 * w])) >> 7) << 1) |
151                ((A_VAL(&(src_ptr[2 * w])) >> 7) << 2) |
152                ((A_VAL(&(src_ptr[3 * w])) >> 7) << 3) |
153                ((A_VAL(&(src_ptr[4 * w])) >> 7) << 4) |
154                ((A_VAL(&(src_ptr[5 * w])) >> 7) << 5) |
155                ((A_VAL(&(src_ptr[6 * w])) >> 7) << 6) |
156                ((A_VAL(&(src_ptr[7 * w])) >> 7) << 7);
157              src_ptr += 8 * w;
158              dst_ptr++;
159           }
160      }
161    h += 7;
162    for (; yy < h; yy ++)
163      {
164         xcb_image_put_pixel(xcbob->xim, yy, y, A_VAL(src_ptr) >> 7);
165         src_ptr += w;
166      }
167 }
168
169 void 
170 evas_software_xcb_write_mask_line_vert_rev(Outbuf *buf, Xcb_Output_Buffer *xcbob, DATA32 *src, int h, int y, int w) 
171 {
172    int yy, bpl = 0;
173    DATA32 *src_ptr;
174    DATA8 *dst_ptr;
175
176    src_ptr = src + ((h - 1) * w);
177    dst_ptr = evas_software_xcb_output_buffer_data(xcbob, &bpl);
178    dst_ptr = dst_ptr + (bpl * y);
179    h -= 7;
180    if (buf->priv.x11.xcb.bit_swap)
181      {
182         for (yy = 0; yy < h; yy += 8)
183           {
184              *dst_ptr =
185                ((A_VAL(&(src_ptr[ 0 * w])) >> 7) << 7) |
186                ((A_VAL(&(src_ptr[-1 * w])) >> 7) << 6) |
187                ((A_VAL(&(src_ptr[-2 * w])) >> 7) << 5) |
188                ((A_VAL(&(src_ptr[-3 * w])) >> 7) << 4) |
189                ((A_VAL(&(src_ptr[-4 * w])) >> 7) << 3) |
190                ((A_VAL(&(src_ptr[-5 * w])) >> 7) << 2) |
191                ((A_VAL(&(src_ptr[-6 * w])) >> 7) << 1) |
192                ((A_VAL(&(src_ptr[-7 * w])) >> 7) << 0);
193              src_ptr -= 8 * w;
194              dst_ptr++;
195           }
196      }
197    else
198      {
199         for (yy = 0; yy < h; yy += 8)
200           {
201              *dst_ptr =
202                ((A_VAL(&(src_ptr[ 0 * w])) >> 7) << 0) |
203                ((A_VAL(&(src_ptr[-1 * w])) >> 7) << 1) |
204                ((A_VAL(&(src_ptr[-2 * w])) >> 7) << 2) |
205                ((A_VAL(&(src_ptr[-3 * w])) >> 7) << 3) |
206                ((A_VAL(&(src_ptr[-4 * w])) >> 7) << 4) |
207                ((A_VAL(&(src_ptr[-5 * w])) >> 7) << 5) |
208                ((A_VAL(&(src_ptr[-6 * w])) >> 7) << 6) |
209                ((A_VAL(&(src_ptr[-7 * w])) >> 7) << 7);
210              src_ptr -= 8 * w;
211              dst_ptr++;
212           }
213      }
214    h += 7;
215    for (; yy < h; yy ++)
216      {
217         xcb_image_put_pixel(xcbob->xim, yy, y, A_VAL(src_ptr) >> 7);
218         src_ptr -= w;
219      }
220 }
221
222 Eina_Bool 
223 evas_software_xcb_can_do_shm(xcb_connection_t *conn, xcb_screen_t *screen) 
224 {
225    static xcb_connection_t *cached_conn = NULL;
226    static int cached_result = 0;
227    Xcb_Output_Buffer *xcbob = NULL;
228    xcb_visualtype_t *visual;
229
230    if (conn == cached_conn) return cached_result;
231    cached_conn = conn;
232
233    visual = _xcbob_find_visual_by_id(screen, screen->root_visual);
234
235    xcbob = 
236      evas_software_xcb_output_buffer_new(conn, visual, screen->root_depth,
237                                          1, 1, EINA_TRUE, NULL);
238    if (!xcbob)
239      cached_result = 0;
240    else 
241      {
242         evas_software_xcb_output_buffer_free(xcbob, EINA_TRUE);
243         cached_result = 1;
244      }
245
246    return cached_result;
247 }
248
249 Xcb_Output_Buffer *
250 evas_software_xcb_output_buffer_new(xcb_connection_t *conn, xcb_visualtype_t *vis, int depth, int w, int h, Eina_Bool try_shm, unsigned char *data) 
251 {
252    Xcb_Output_Buffer *xcbob = NULL;
253
254    if (!(xcbob = calloc(1, sizeof(Xcb_Output_Buffer))))
255      return NULL;
256
257    xcbob->connection = conn;
258    xcbob->visual = vis;
259    xcbob->xim = NULL;
260    xcbob->shm_info = NULL;
261    xcbob->w = w;
262    xcbob->h = h;
263    xcbob->data = data;
264
265    if (try_shm) 
266      {
267         xcbob->shm_info = malloc(sizeof(xcb_shm_segment_info_t));
268         if (xcbob->shm_info) 
269           {
270              xcbob->shm_info->shmseg = xcb_generate_id(conn);
271              xcbob->xim = 
272                _xcbob_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, 
273                                     depth, NULL, ~0, NULL);
274              if (xcbob->xim) 
275                {
276                   xcbob->shm_info->shmid = 
277                     shmget(IPC_PRIVATE, xcbob->xim->size, (IPC_CREAT | 0666));
278                   if (xcbob->shm_info->shmid == (uint32_t)-1) 
279                     {
280                        xcb_image_destroy(xcbob->xim);
281                        free(xcbob->shm_info);
282                        free(xcbob);
283                        return NULL;
284                     }
285                   xcbob->shm_info->shmaddr = 
286                     shmat(xcbob->shm_info->shmid, 0, 0);
287                   if (xcbob->shm_info->shmaddr != ((void *)-1))
288                     {
289                        xcbob->xim->data = xcbob->shm_info->shmaddr;
290                        xcb_shm_attach(conn, xcbob->shm_info->shmseg, 
291                                       xcbob->shm_info->shmid, 0);
292                        xcbob->bpl = xcbob->xim->stride;
293                        xcbob->psize = (xcbob->bpl * xcbob->h);
294                        return xcbob;
295                     }
296                   else 
297                     {
298                        shmctl(xcbob->shm_info->shmid, IPC_RMID, 0);
299                        xcb_image_destroy(xcbob->xim);
300                        free(xcbob->shm_info);
301                        free(xcbob);
302                        return NULL;
303                     }
304                }
305              else 
306                {
307                   free(xcbob->shm_info);
308                   free(xcbob);
309                   return NULL;
310                }
311           }
312         else 
313           {
314              free(xcbob);
315              return NULL;
316           }
317      }
318    else 
319      {
320         /* no shm */
321         xcbob->xim = 
322           _xcbob_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, 
323                                depth, NULL, ~0, NULL);
324         if (!xcbob->xim) 
325           {
326              free(xcbob);
327              return NULL;
328           }
329         if (!xcbob->xim->data) 
330           {
331              xcbob->xim->data = malloc(xcbob->xim->size);
332              if (!xcbob->xim->data) 
333                {
334                   xcb_image_destroy(xcbob->xim);
335                   free(xcbob);
336                   return NULL;
337                }
338           }
339         xcbob->bpl = xcbob->xim->stride;
340         xcbob->psize = xcbob->xim->size;
341      }
342    return xcbob;
343 }
344
345 void 
346 evas_software_xcb_output_buffer_free(Xcb_Output_Buffer *xcbob, Eina_Bool sync) 
347 {
348    if (xcbob->shm_info) 
349      {
350         if (sync) _xcbob_sync(xcbob->connection);
351         xcb_shm_detach(xcbob->connection, xcbob->shm_info->shmseg);
352         xcb_image_destroy(xcbob->xim);
353         shmdt(xcbob->shm_info->shmaddr);
354         shmctl(xcbob->shm_info->shmid, IPC_RMID, 0);
355         free(xcbob->shm_info);
356      }
357    else 
358      {
359         if (xcbob->data) xcbob->xim->data = NULL;
360         free(xcbob->xim->data);
361         xcb_image_destroy(xcbob->xim);
362      }
363    free(xcbob);
364 }
365
366 void 
367 evas_software_xcb_output_buffer_paste(Xcb_Output_Buffer *xcbob, xcb_drawable_t drawable, xcb_gcontext_t gc, int x, int y, Eina_Bool sync) 
368 {
369    if (xcbob->shm_info) 
370      {
371         xcb_image_shm_put(xcbob->connection, drawable, gc, xcbob->xim, 
372                           *xcbob->shm_info, 0, 0, x, y, xcbob->w, xcbob->h, 0);
373         if (sync) _xcbob_sync(xcbob->connection);
374      }
375    else 
376      xcb_image_put(xcbob->connection, drawable, gc, xcbob->xim, x, y, 0);
377 }
378
379 DATA8 *
380 evas_software_xcb_output_buffer_data(Xcb_Output_Buffer *xcbob, int *bpl_ret) 
381 {
382    if (bpl_ret) *bpl_ret = xcbob->xim->stride;
383    return xcbob->xim->data;
384 }
385
386 int 
387 evas_software_xcb_output_buffer_depth(Xcb_Output_Buffer *xcbob) 
388 {
389    return xcbob->xim->bpp;
390 }
391
392 int 
393 evas_software_xcb_output_buffer_byte_order(Xcb_Output_Buffer *xcbob) 
394 {
395    return xcbob->xim->byte_order;
396 }
397
398 int 
399 evas_software_xcb_output_buffer_bit_order(Xcb_Output_Buffer *xcbob) 
400 {
401    return xcbob->xim->bit_order;
402 }
403
404 /* local functions */
405 static void 
406 _xcbob_sync(xcb_connection_t *conn) 
407 {
408    free(xcb_get_input_focus_reply(conn, 
409                                   xcb_get_input_focus_unchecked(conn), NULL));
410 }
411
412 static xcb_image_t *
413 _xcbob_create_native(xcb_connection_t *conn, int w, int h, xcb_image_format_t format, uint8_t depth, void *base, uint32_t bytes, uint8_t *data) 
414 {
415    const xcb_setup_t *setup;
416    xcb_format_t *fmt = NULL;
417    xcb_image_format_t xif;
418
419    /* NB: We cannot use xcb_image_create_native as it only creates images 
420     * using MSB_FIRST, so this routine recreates that function and checks 
421     * endian-ness correctly */
422    setup = xcb_get_setup(conn);
423    xif = format;
424
425    if ((xif == XCB_IMAGE_FORMAT_Z_PIXMAP) && (depth == 1))
426      xif = XCB_IMAGE_FORMAT_XY_PIXMAP;
427
428    fmt = _xcbob_find_format(setup, depth);
429    if (!fmt) return 0;
430
431    switch (xif) 
432      {
433       case XCB_IMAGE_FORMAT_XY_BITMAP:
434         if (depth != 1) return 0;
435       case XCB_IMAGE_FORMAT_XY_PIXMAP:
436         return xcb_image_create(w, h, xif, 
437                                 fmt->scanline_pad, 
438                                 fmt->depth, fmt->bits_per_pixel, 
439                                 setup->bitmap_format_scanline_unit, 
440                                 setup->image_byte_order, 
441                                 setup->bitmap_format_bit_order, 
442                                 base, bytes, data);
443       case XCB_IMAGE_FORMAT_Z_PIXMAP:
444         return xcb_image_create(w, h, xif, 
445                                 fmt->scanline_pad, 
446                                 fmt->depth, fmt->bits_per_pixel, 
447                                 setup->bitmap_format_scanline_unit, 
448                                 setup->image_byte_order, 
449                                 setup->bitmap_format_bit_order, 
450                                 base, bytes, data);
451       default:
452         break;
453      }
454
455    return 0;
456 }
457
458 static xcb_format_t *
459 _xcbob_find_format(const xcb_setup_t *setup, uint8_t depth) 
460 {
461    xcb_format_t *fmt, *fmtend;
462
463    fmt = xcb_setup_pixmap_formats(setup);
464    fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
465    for (; fmt != fmtend; ++fmt)
466      if (fmt->depth == depth) 
467        return fmt;
468
469    return 0;
470 }
471
472 static xcb_visualtype_t *
473 _xcbob_find_visual_by_id(xcb_screen_t *screen, xcb_visualid_t id) 
474 {
475    xcb_depth_iterator_t diter;
476    xcb_visualtype_iterator_t viter;
477
478    diter = xcb_screen_allowed_depths_iterator(screen);
479    for (; diter.rem; xcb_depth_next(&diter)) 
480      {
481         viter = xcb_depth_visuals_iterator(diter.data);
482         for (; viter.rem; xcb_visualtype_next(&viter)) 
483           {
484              if (viter.data->visual_id == id)
485                return viter.data;
486           }
487      }
488
489    return 0;
490 }