diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_cursor.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_cursor.c b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_cursor.c new file mode 100644 index 0000000..755df04 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_cursor.c | |||
@@ -0,0 +1,400 @@ | |||
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 | |||