Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb_cursor.c
1 #include "ecore_xcb_private.h"
2 #ifdef ECORE_XCB_CURSOR
3 # include <xcb/render.h>
4 # include <xcb/xcb_renderutil.h>
5 #endif
6
7 /* local function prototypes */
8 #ifdef ECORE_XCB_CURSOR
9 static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format_get(void);
10 #endif
11 static void                       _ecore_xcb_cursor_default_size_get(void);
12 static void                       _ecore_xcb_cursor_dpi_size_get(void);
13 static void                       _ecore_xcb_cursor_guess_size(void);
14 #ifdef ECORE_XCB_CURSOR
15 static Ecore_X_Cursor             _ecore_xcb_cursor_image_load_cursor(xcb_image_t *img,
16                                                                       int          hot_x,
17                                                                       int          hot_y);
18 #endif
19 static void _ecore_xcb_cursor_image_destroy(xcb_image_t *img);
20
21 /* local variables */
22 static int _ecore_xcb_cursor_size = 0;
23 static Eina_Bool _ecore_xcb_cursor = EINA_FALSE;
24 #ifdef ECORE_XCB_CURSOR
25 static uint32_t _ecore_xcb_cursor_format_id = 0;
26 //   static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format = NULL;
27 #endif
28
29 void
30 _ecore_xcb_cursor_init(void)
31 {
32    LOGFN(__FILE__, __LINE__, __FUNCTION__);
33    /* NB: No-op */
34 }
35
36 void
37 _ecore_xcb_cursor_finalize(void)
38 {
39    LOGFN(__FILE__, __LINE__, __FUNCTION__);
40
41 #ifdef ECORE_XCB_CURSOR
42    _ecore_xcb_cursor = _ecore_xcb_render_argb_get();
43
44    /* find render pict format */
45    if (_ecore_xcb_cursor_format_id <= 0)
46      _ecore_xcb_cursor_format_id = _ecore_xcb_cursor_format_get()->id;
47 #endif
48
49    /* try to grab cursor size from XDefaults */
50    _ecore_xcb_cursor_default_size_get();
51
52    /* if that failed, try to get it from Xft Dpi setting */
53    if (_ecore_xcb_cursor_size == 0)
54      _ecore_xcb_cursor_dpi_size_get();
55
56    /* if that failed, try to guess from display size */
57    if (_ecore_xcb_cursor_size == 0)
58      _ecore_xcb_cursor_guess_size();
59
60    /* NB: Would normally add theme stuff here, but E cursor does not support
61     * xcursor themes. Delay parsing that stuff out until such time if/when the
62     * user selects to use X Cursor, rather than E cursor */
63 }
64
65 EAPI Eina_Bool
66 ecore_x_cursor_color_supported_get(void)
67 {
68    LOGFN(__FILE__, __LINE__, __FUNCTION__);
69
70    return _ecore_xcb_cursor;
71 }
72
73 EAPI Ecore_X_Cursor
74 ecore_x_cursor_new(Ecore_X_Window win,
75                    int           *pixels,
76                    int            w,
77                    int            h,
78                    int            hot_x,
79                    int            hot_y)
80 {
81    Ecore_X_Cursor cursor = 0;
82    xcb_image_t *img;
83
84 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
85    CHECK_XCB_CONN;
86
87 #ifdef ECORE_XCB_CURSOR
88    if (_ecore_xcb_cursor)
89      {
90         img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
91                                              32, NULL, (w * h * sizeof(int)),
92                                              (uint8_t *)pixels);
93         cursor = _ecore_xcb_cursor_image_load_cursor(img, hot_x, hot_y);
94         _ecore_xcb_cursor_image_destroy(img);
95         return cursor;
96      }
97    else
98 #endif
99    {
100       Ecore_X_GC gc;
101       xcb_pixmap_t pmap, mask;
102       uint32_t *pix;
103       uint8_t fr = 0x00, fg = 0x00, fb = 0x00;
104       uint8_t br = 0xff, bg = 0xff, bb = 0xff;
105       uint32_t brightest = 0, darkest = 255 * 3;
106       uint16_t x, y;
107       const uint32_t dither[2][2] =
108       {
109          {0, 2},
110          {3, 1}
111       };
112
113       img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
114                                            1, NULL, ~0, NULL);
115       if (img->data) free(img->data);
116       img->data = malloc(img->size);
117
118       pmap = xcb_generate_id(_ecore_xcb_conn);
119       xcb_create_pixmap(_ecore_xcb_conn, 1, pmap, win, w, h);
120       mask = xcb_generate_id(_ecore_xcb_conn);
121       xcb_create_pixmap(_ecore_xcb_conn, 1, mask, win, w, h);
122
123       pix = (uint32_t *)pixels;
124       for (y = 0; y < h; y++)
125         {
126            for (x = 0; x < w; x++)
127              {
128                 uint8_t r, g, b, a;
129
130                 a = (pix[0] >> 24) & 0xff;
131                 r = (pix[0] >> 16) & 0xff;
132                 g = (pix[0] >> 8) & 0xff;
133                 b = (pix[0]) & 0xff;
134                 if (a > 0)
135                   {
136                      if ((uint32_t)(r + g + b) > brightest)
137                        {
138                           brightest = r + g + b;
139                           br = r;
140                           bg = g;
141                           bb = b;
142                        }
143
144                      if ((uint32_t)(r + g + b) < darkest)
145                        {
146                           darkest = r + g + b;
147                           fr = r;
148                           fg = g;
149                           fb = b;
150                        }
151                   }
152                 pix++;
153              }
154         }
155
156       pix = (uint32_t *)pixels;
157       for (y = 0; y < h; y++)
158         {
159            for (x = 0; x < w; x++)
160              {
161                 uint32_t v;
162                 uint8_t r, g, b;
163                 int32_t d1, d2;
164
165                 r = (pix[0] >> 16) & 0xff;
166                 g = (pix[0] >> 8) & 0xff;
167                 b = (pix[0]) & 0xff;
168                 d1 =
169                   ((r - fr) * (r - fr)) +
170                   ((g - fg) * (g - fg)) +
171                   ((b - fb) * (b - fb));
172                 d2 =
173                   ((r - br) * (r - br)) +
174                   ((g - bg) * (g - bg)) +
175                   ((b - bb) * (b - bb));
176                 if (d1 + d2)
177                   {
178                      v = (((d2 * 255) / (d1 + d2)) * 5) / 256;
179                      if (v > dither[x & 0x1][y & 0x1])
180                        v = 1;
181                      else
182                        v = 0;
183                   }
184                 else
185                   v = 0;
186
187                 xcb_image_put_pixel(img, x, y, v);
188                 pix++;
189              }
190         }
191
192       gc = ecore_x_gc_new(pmap, 0, NULL);
193       xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc, w, h,
194                     0, 0, 0, img->depth, img->size, img->data);
195       ecore_x_gc_free(gc);
196
197       pix = (uint32_t *)pixels;
198       for (y = 0; y < h; y++)
199         {
200            for (x = 0; x < w; x++)
201              {
202                 uint32_t v;
203
204                 v = (((pix[0] >> 24) & 0xff) * 5) / 256;
205                 if (v > dither[x & 0x1][y & 0x1])
206                   v = 1;
207                 else
208                   v = 0;
209
210                 xcb_image_put_pixel(img, x, y, v);
211                 pix++;
212              }
213         }
214
215       gc = ecore_x_gc_new(mask, 0, NULL);
216       xcb_put_image(_ecore_xcb_conn, img->format, mask, gc, w, h,
217                     0, 0, 0, img->depth, img->size, img->data);
218       ecore_x_gc_free(gc);
219
220       if (img->data) free(img->data);
221       _ecore_xcb_cursor_image_destroy(img);
222
223       cursor = xcb_generate_id(_ecore_xcb_conn);
224       xcb_create_cursor(_ecore_xcb_conn, cursor, pmap, mask,
225                         fr << 8 | fr, fg << 8 | fg, fb << 8 | fb,
226                         br << 8 | br, bg << 8 | bg, bb << 8 | bb,
227                         hot_x, hot_y);
228
229       xcb_free_pixmap(_ecore_xcb_conn, pmap);
230       xcb_free_pixmap(_ecore_xcb_conn, mask);
231
232       return cursor;
233    }
234
235    return 0;
236 }
237
238 EAPI void
239 ecore_x_cursor_free(Ecore_X_Cursor c)
240 {
241 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
242      CHECK_XCB_CONN;
243
244      xcb_free_cursor(_ecore_xcb_conn, c);
245 }
246
247 /*
248  * Returns the cursor for the given shape.
249  * Note that the return value must not be freed with
250  * ecore_x_cursor_free()!
251  */
252 EAPI Ecore_X_Cursor
253 ecore_x_cursor_shape_get(int shape)
254 {
255    Ecore_X_Cursor cursor = 0;
256    xcb_font_t font;
257
258    LOGFN(__FILE__, __LINE__, __FUNCTION__);
259    CHECK_XCB_CONN;
260
261    font = xcb_generate_id(_ecore_xcb_conn);
262    xcb_open_font(_ecore_xcb_conn, font, strlen("cursor"), "cursor");
263
264    cursor = xcb_generate_id(_ecore_xcb_conn);
265    /* FIXME: Add request check ?? */
266    xcb_create_glyph_cursor(_ecore_xcb_conn, cursor, font, font,
267                            shape, shape + 1, 0, 0, 0, 65535, 65535, 65535);
268
269    xcb_close_font(_ecore_xcb_conn, font);
270    return cursor;
271 }
272
273 EAPI void
274 ecore_x_cursor_size_set(int size)
275 {
276    LOGFN(__FILE__, __LINE__, __FUNCTION__);
277
278    _ecore_xcb_cursor_size = size;
279    /* NB: May need to adjust size of current cursors here */
280 }
281
282 EAPI int
283 ecore_x_cursor_size_get(void)
284 {
285    LOGFN(__FILE__, __LINE__, __FUNCTION__);
286
287    return _ecore_xcb_cursor_size;
288 }
289
290 /* local functions */
291 #ifdef ECORE_XCB_CURSOR
292 static xcb_render_pictforminfo_t *
293 _ecore_xcb_cursor_format_get(void)
294 {
295    const xcb_render_query_pict_formats_reply_t *reply;
296    xcb_render_pictforminfo_t *ret = NULL;
297
298    CHECK_XCB_CONN;
299
300    reply = xcb_render_util_query_formats(_ecore_xcb_conn);
301    if (reply)
302      ret = xcb_render_util_find_standard_format(reply,
303                                                 XCB_PICT_STANDARD_ARGB_32);
304
305    return ret;
306 }
307
308 #endif
309
310 static void
311 _ecore_xcb_cursor_default_size_get(void)
312 {
313    char *s = NULL;
314    int v = 0;
315
316    LOGFN(__FILE__, __LINE__, __FUNCTION__);
317
318    s = getenv("XCURSOR_SIZE");
319    if (!s)
320      {
321         _ecore_xcb_xdefaults_init();
322         v = _ecore_xcb_xdefaults_int_get("Xcursor", "size");
323         _ecore_xcb_xdefaults_shutdown();
324      }
325    else
326      v = atoi(s);
327    if (v) _ecore_xcb_cursor_size = ((v * 16) / 72);
328 }
329
330 static void
331 _ecore_xcb_cursor_dpi_size_get(void)
332 {
333    int v = 0;
334
335    LOGFN(__FILE__, __LINE__, __FUNCTION__);
336
337    _ecore_xcb_xdefaults_init();
338    v = _ecore_xcb_xdefaults_int_get("Xft", "dpi");
339    if (v) _ecore_xcb_cursor_size = ((v * 16) / 72);
340    _ecore_xcb_xdefaults_shutdown();
341 }
342
343 static void
344 _ecore_xcb_cursor_guess_size(void)
345 {
346    int w = 0, h = 0, s = 0;
347
348    LOGFN(__FILE__, __LINE__, __FUNCTION__);
349
350    ecore_x_screen_size_get(_ecore_xcb_screen, &w, &h);
351    if (h < w) s = h;
352    else s = w;
353    _ecore_xcb_cursor_size = (s / 48);
354 }
355
356 #ifdef ECORE_XCB_CURSOR
357 static Ecore_X_Cursor
358 _ecore_xcb_cursor_image_load_cursor(xcb_image_t *img,
359                                     int          hot_x,
360                                     int          hot_y)
361 {
362    Ecore_X_Cursor cursor = 0;
363    Ecore_X_GC gc;
364    xcb_pixmap_t pmap;
365    xcb_render_picture_t pict;
366
367    CHECK_XCB_CONN;
368
369    pmap = xcb_generate_id(_ecore_xcb_conn);
370    xcb_create_pixmap(_ecore_xcb_conn, img->depth, pmap,
371                      ((xcb_screen_t *)_ecore_xcb_screen)->root,
372                      img->width, img->height);
373
374    gc = ecore_x_gc_new(pmap, 0, NULL);
375    xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc,
376                  img->width, img->height, 0, 0, 0, img->depth,
377                  img->size, img->data);
378    ecore_x_gc_free(gc);
379
380    pict = xcb_generate_id(_ecore_xcb_conn);
381    xcb_render_create_picture(_ecore_xcb_conn, pict, pmap,
382                              _ecore_xcb_cursor_format_id, 0, NULL);
383    xcb_free_pixmap(_ecore_xcb_conn, pmap);
384
385    cursor = xcb_generate_id(_ecore_xcb_conn);
386    xcb_render_create_cursor(_ecore_xcb_conn, cursor, pict, hot_x, hot_y);
387    xcb_render_free_picture(_ecore_xcb_conn, pict);
388
389    return cursor;
390 }
391
392 #endif
393
394 static void
395 _ecore_xcb_cursor_image_destroy(xcb_image_t *img)
396 {
397    CHECK_XCB_CONN;
398    if (img) xcb_image_destroy(img);
399 }
400