f71d595d39d1fdf42d0fd47e2e031d7dabe074ab
[profile/ivi/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb_cursor.c
1 #include "ecore_xcb_private.h"
2 # include <xcb/xproto.h>
3 # include <xcb/xcb_image.h>
4 #ifdef ECORE_XCB_CURSOR
5 # include <xcb/render.h>
6 # include <xcb/xcb_renderutil.h>
7 #endif
8
9 /* local function prototypes */
10 static xcb_image_t *_ecore_xcb_cursor_image_create(int w, int h, int *pixels);
11 static Ecore_X_Cursor _ecore_xcb_cursor_image_load_cursor(Ecore_X_Window win, int w, int h, int hot_x, int hot_y, int *pixels, xcb_image_t *img);
12 #ifdef ECORE_XCB_CURSOR
13 static Ecore_X_Cursor _ecore_xcb_cursor_image_load_argb_cursor(Ecore_X_Window win, int w, int h, int hot_x, int hot_y, xcb_image_t *img);
14 static xcb_render_pictforminfo_t *_ecore_xcb_cursor_find_image_format(void);
15 #endif
16
17 /* local variables */
18 #ifdef ECORE_XCB_CURSOR
19 static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format = NULL;
20 #endif
21 static int _ecore_xcb_cursor_size = 0;
22 static Eina_Bool _ecore_xcb_cursor = EINA_FALSE;
23
24 void 
25 _ecore_xcb_cursor_init(void) 
26 {
27    LOGFN(__FILE__, __LINE__, __FUNCTION__);
28
29 #ifdef ECORE_XCB_CURSOR
30    /* NB: noop */
31 #endif
32 }
33
34 void 
35 _ecore_xcb_cursor_finalize(void) 
36 {
37    LOGFN(__FILE__, __LINE__, __FUNCTION__);
38
39 #ifdef ECORE_XCB_CURSOR
40    _ecore_xcb_cursor = _ecore_xcb_render_argb_get();
41 #endif
42 }
43
44 /*
45  * Returns the cursor for the given shape.
46  * Note that the return value must not be freed with
47  * ecore_x_cursor_free()!
48  */
49 EAPI Ecore_X_Cursor 
50 ecore_x_cursor_shape_get(int shape) 
51 {
52    Ecore_X_Cursor cursor = 0;
53    xcb_font_t font;
54
55    LOGFN(__FILE__, __LINE__, __FUNCTION__);
56
57    font = xcb_generate_id(_ecore_xcb_conn);
58    xcb_open_font(_ecore_xcb_conn, font, strlen("cursor"), "cursor");
59
60    cursor = xcb_generate_id(_ecore_xcb_conn);
61    xcb_create_glyph_cursor(_ecore_xcb_conn, cursor, font, font, 
62                            shape, shape + 1, 0, 0, 0, 65535, 65535, 65535);
63    xcb_close_font(_ecore_xcb_conn, font);
64
65    return cursor;
66 }
67
68 EAPI void 
69 ecore_x_cursor_free(Ecore_X_Cursor cursor) 
70 {
71    LOGFN(__FILE__, __LINE__, __FUNCTION__);
72
73    xcb_free_cursor(_ecore_xcb_conn, cursor);
74 }
75
76 EAPI Eina_Bool 
77 ecore_x_cursor_color_supported_get(void) 
78 {
79    LOGFN(__FILE__, __LINE__, __FUNCTION__);
80
81    return _ecore_xcb_cursor;
82 }
83
84 EAPI Ecore_X_Cursor 
85 ecore_x_cursor_new(Ecore_X_Window win, int *pixels, int w, int h, int hot_x, int hot_y) 
86 {
87    Ecore_X_Cursor cursor = 0;
88    xcb_image_t *img;
89
90    LOGFN(__FILE__, __LINE__, __FUNCTION__);
91
92    if (_ecore_xcb_cursor) // argb
93      {
94         if ((img = _ecore_xcb_cursor_image_create(w, h, pixels)))
95           {
96 #ifdef ECORE_XCB_CURSOR
97              cursor = 
98                _ecore_xcb_cursor_image_load_argb_cursor(win, w, h, 
99                                                         hot_x, hot_y, img);
100 #else
101              cursor = 
102                _ecore_xcb_cursor_image_load_cursor(win, w, h, 
103                                                    hot_x, hot_y, pixels, img);
104 #endif
105           }
106         else
107           DBG("Failed to create new cursor image");
108      }
109    else 
110      {
111         if ((img = _ecore_xcb_cursor_image_create(w, h, pixels)))
112           {
113              cursor = 
114                _ecore_xcb_cursor_image_load_cursor(win, w, h, 
115                                                    hot_x, hot_y, pixels, img);
116           }
117         else
118           DBG("Failed to create new cursor image");
119      }
120
121    if (cursor) 
122      {
123         uint32_t mask, list;
124
125         mask = XCB_CW_CURSOR;
126         list = cursor;
127         xcb_change_window_attributes(_ecore_xcb_conn, win, mask, &list);
128      }
129
130    return cursor;
131 }
132
133 EAPI void 
134 ecore_x_cursor_size_set(int size) 
135 {
136    LOGFN(__FILE__, __LINE__, __FUNCTION__);
137
138    // NB: size_set only needed for non-argb cursors
139    _ecore_xcb_cursor_size = size;
140 }
141
142 EAPI int 
143 ecore_x_cursor_size_get(void) 
144 {
145    LOGFN(__FILE__, __LINE__, __FUNCTION__);
146
147    return _ecore_xcb_cursor_size;
148 }
149
150 /* local functions */
151 static xcb_image_t *
152 _ecore_xcb_cursor_image_create(int w, int h, int *pixels) 
153 {
154    // NB: May be able to use shm here, but the image NEEDS to be in 
155    // native format
156    if (_ecore_xcb_cursor) 
157      {
158 #ifdef ECORE_XCB_CURSOR
159         return xcb_image_create_native(_ecore_xcb_conn, w, h, 
160                                        XCB_IMAGE_FORMAT_Z_PIXMAP, 
161                                        32, pixels, (w * h * sizeof(int)), // 32
162                                        (uint8_t *)pixels);
163 #else
164         return xcb_image_create_native(_ecore_xcb_conn, w, h, 
165                                        XCB_IMAGE_FORMAT_Z_PIXMAP, 
166                                        1, pixels, (w * h * sizeof(int)), // 32
167                                        (uint8_t *)pixels);
168 #endif
169      }
170    else 
171      {
172         return xcb_image_create_native(_ecore_xcb_conn, w, h, 
173                                        XCB_IMAGE_FORMAT_Z_PIXMAP, 1, 
174                                        NULL, ~0, NULL);
175      }
176 }
177
178 static Ecore_X_Cursor 
179 _ecore_xcb_cursor_image_load_cursor(Ecore_X_Window win, int w, int h, int hot_x, int hot_y, int *pixels, xcb_image_t *img) 
180 {
181    xcb_pixmap_t pixmap, mask;
182    Ecore_X_Cursor cursor;
183    Ecore_X_GC gc;
184    uint32_t *pix;
185    uint8_t fr = 0x00, fg = 0x00, fb = 0x00;
186    uint8_t br = 0xff, bg = 0xff, bb = 0xff;
187    uint32_t brightest = 0, darkest = 255 * 3;
188    uint16_t x, y;
189    const uint32_t dither[2][2] =
190      {
191         {0, 2},
192         {3, 1}
193      };
194
195    pixmap = xcb_generate_id(_ecore_xcb_conn);
196    xcb_create_pixmap(_ecore_xcb_conn, 1, pixmap, win, w, h);
197
198    mask = xcb_generate_id(_ecore_xcb_conn);
199    xcb_create_pixmap(_ecore_xcb_conn, 1, mask, win, w, h);
200
201    img->data = malloc(img->size);
202
203    pix = (uint32_t *)pixels;
204    for (y = 0; y < h; y++)
205      {
206         for (x = 0; x < w; x++)
207           {
208              uint8_t r, g, b, a;
209
210              a = (pix[0] >> 24) & 0xff;
211              r = (pix[0] >> 16) & 0xff;
212              g = (pix[0] >> 8) & 0xff;
213              b = (pix[0]) & 0xff;
214              if (a > 0)
215                {
216                   if ((uint32_t)(r + g + b) > brightest)
217                     {
218                        brightest = r + g + b;
219                        br = r;
220                        bg = g;
221                        bb = b;
222                     }
223
224                   if ((uint32_t)(r + g + b) < darkest)
225                     {
226                        darkest = r + g + b;
227                        fr = r;
228                        fg = g;
229                        fb = b;
230                     }
231                }
232              pix++;
233           }
234      }
235
236    pix = (uint32_t *)pixels;
237    for (y = 0; y < h; y++)
238      {
239         for (x = 0; x < w; x++)
240           {
241              uint32_t v;
242              uint8_t r, g, b;
243              int32_t d1, d2;
244
245              r = (pix[0] >> 16) & 0xff;
246              g = (pix[0] >> 8) & 0xff;
247              b = (pix[0]) & 0xff;
248              d1 =
249                ((r - fr) * (r - fr)) +
250                ((g - fg) * (g - fg)) +
251                ((b - fb) * (b - fb));
252              d2 =
253                ((r - br) * (r - br)) +
254                ((g - bg) * (g - bg)) +
255                ((b - bb) * (b - bb));
256              if (d1 + d2)
257                {
258                   v = (((d2 * 255) / (d1 + d2)) * 5) / 256;
259                   if (v > dither[x & 0x1][y & 0x1])
260                     v = 1;
261                   else
262                     v = 0;
263                }
264              else
265                v = 0;
266
267              xcb_image_put_pixel(img, x, y, v);
268              pix++;
269           }
270      }
271
272    // img->depth was 1
273    gc = ecore_x_gc_new(pixmap, 0, NULL);
274    xcb_put_image(_ecore_xcb_conn, XCB_IMAGE_FORMAT_Z_PIXMAP, 
275                  pixmap, gc, w, h, 0, 0, 0, img->depth, img->size, img->data);
276    ecore_x_gc_free(gc);
277
278    pix = (uint32_t *)pixels;
279    for (y = 0; y < h; y++)
280      {
281         for (x = 0; x < w; x++)
282           {
283              uint32_t v;
284
285              v = (((pix[0] >> 24) & 0xff) * 5) / 256;
286              if (v > dither[x & 0x1][y & 0x1])
287                v = 1;
288              else
289                v = 0;
290
291              xcb_image_put_pixel(img, x, y, v);
292              pix++;
293           }
294      }
295
296    // img->depth was 1
297    gc = ecore_x_gc_new(mask, 0, NULL);
298    xcb_put_image(_ecore_xcb_conn, XCB_IMAGE_FORMAT_Z_PIXMAP, 
299                  mask, gc, w, h, 0, 0, 0, img->depth, img->size, img->data);
300    ecore_x_gc_free(gc);
301
302    cursor = xcb_generate_id(_ecore_xcb_conn);
303    xcb_create_cursor(_ecore_xcb_conn, cursor, pixmap, mask, 
304                      fr << 8 | fr, fg << 8 | fg, fb << 8 | fb,
305                      br << 8 | br, bg << 8 | bg, bb << 8 | bb, 
306                      hot_x, hot_y);
307
308    xcb_free_pixmap(_ecore_xcb_conn, pixmap);
309    xcb_free_pixmap(_ecore_xcb_conn, mask);
310
311    return cursor;
312 }
313
314 #ifdef ECORE_XCB_CURSOR
315 static Ecore_X_Cursor 
316 _ecore_xcb_cursor_image_load_argb_cursor(Ecore_X_Window win, int w, int h, int hot_x, int hot_y, xcb_image_t *img) 
317 {
318    xcb_pixmap_t pixmap;
319    xcb_render_picture_t pict;
320    Ecore_X_Cursor cursor;
321    Ecore_X_GC gc;
322
323    if (!_ecore_xcb_cursor_format) 
324      _ecore_xcb_cursor_format = _ecore_xcb_cursor_find_image_format();
325
326    pixmap = xcb_generate_id(_ecore_xcb_conn);
327    xcb_create_pixmap(_ecore_xcb_conn, 32, pixmap, win, w, h);
328
329    // img->depth was 32
330    gc = ecore_x_gc_new(pixmap, 0, NULL);
331    xcb_put_image(_ecore_xcb_conn, XCB_IMAGE_FORMAT_Z_PIXMAP, 
332                  pixmap, gc, w, h, 0, 0, 0, 
333                  img->depth, img->size, img->data);
334    ecore_x_gc_free(gc);
335
336    pict = xcb_generate_id(_ecore_xcb_conn);
337    xcb_render_create_picture(_ecore_xcb_conn, pict, pixmap, 
338                              _ecore_xcb_cursor_format->id, 0, NULL);
339    xcb_free_pixmap(_ecore_xcb_conn, pixmap);
340
341    cursor = xcb_generate_id(_ecore_xcb_conn);
342    xcb_render_create_cursor(_ecore_xcb_conn, cursor, pict, hot_x, hot_y);
343    xcb_render_free_picture(_ecore_xcb_conn, pict);
344
345    return cursor;
346 }
347
348 static xcb_render_pictforminfo_t *
349 _ecore_xcb_cursor_find_image_format(void)
350 {
351    const xcb_render_query_pict_formats_reply_t *reply;
352    xcb_render_pictforminfo_t *ret = NULL;
353
354    reply = xcb_render_util_query_formats(_ecore_xcb_conn);
355    if (reply) 
356      {
357         ret = xcb_render_util_find_standard_format(reply, 
358                                                    XCB_PICT_STANDARD_ARGB_32);
359 //        free(reply);
360      }
361
362    return ret;
363 }
364 #endif