svn update: 60286 (latest:60286)
[profile/ivi/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb.c
1 #include <string.h>
2
3 #include <X11/keysym.h>
4
5 #include <Ecore.h>
6 #include <Ecore_Input.h>
7
8 #include "ecore_xcb_private.h"
9 #include "Ecore_X_Atoms.h"
10
11 static Eina_Bool      _ecore_xcb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
12 static Eina_Bool      _ecore_xcb_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler);
13 static int            _ecore_xcb_key_mask_get(xcb_keysym_t sym);
14 static int            _ecore_xcb_event_modifier(unsigned int state);
15
16 static void *         _ecore_xcb_event_filter_start(void *data);
17 static Eina_Bool      _ecore_xcb_event_filter_filter(void *data, void *loop_data,int type, void *event);
18 static void           _ecore_xcb_event_filter_end(void *data, void *loop_data);
19
20 static Ecore_Fd_Handler *_ecore_xcb_fd_handler_handle = NULL;
21 static Ecore_Event_Filter *_ecore_xcb_filter_handler = NULL;
22
23 static const int XCB_EVENT_ANY = 0; /* 0 can be used as there are no event types
24                                      * with index 0 and 1 as they are used for
25                                      * errors
26                                      */
27
28 #ifdef ECORE_XCB_DAMAGE
29 static int _ecore_xcb_event_damage_id = 0;
30 #endif /* ECORE_XCB_DAMAGE */
31 #ifdef ECORE_XCB_RANDR
32 static int _ecore_xcb_event_randr_id = 0;
33 #endif /* ECORE_XCB_RANDR */
34 #ifdef ECORE_XCB_SCREENSAVER
35 static int _ecore_xcb_event_screensaver_id = 0;
36 #endif /* ECORE_XCB_SCREENSAVER */
37 #ifdef ECORE_XCB_SHAPE
38 static int _ecore_xcb_event_shape_id = 0;
39 #endif /* ECORE_XCB_SHAPE */
40 #ifdef ECORE_XCB_SYNC
41 static int _ecore_xcb_event_sync_id = 0;
42 #endif /* ECORE_XCB_SYNC */
43 #ifdef ECORE_XCB_FIXES
44 static int _ecore_xcb_event_fixes_selection_id = 0;
45 #endif /* ECORE_XCB_FIXES */
46
47 static int _ecore_xcb_event_handlers_num = 0;
48 static void (**_ecore_xcb_event_handlers) (xcb_generic_event_t * event) = NULL;
49 static xcb_generic_event_t *_ecore_xcb_event_buffered = NULL;
50
51 static int _ecore_xcb_init_count = 0;
52 static int _ecore_xcb_grab_count = 0;
53 int _ecore_x11xcb_log_dom = -1;
54
55 Ecore_X_Connection *_ecore_xcb_conn = NULL;
56 Ecore_X_Screen *_ecore_xcb_screen = NULL;
57 double _ecore_xcb_double_click_time = 0.25;
58 Ecore_X_Time _ecore_xcb_event_last_time = XCB_NONE;
59 Ecore_X_Window _ecore_xcb_event_last_window = XCB_NONE;
60 int16_t _ecore_xcb_event_last_root_x = 0;
61 int16_t _ecore_xcb_event_last_root_y = 0;
62 int _ecore_xcb_xcursor = 0;
63
64 Ecore_X_Window _ecore_xcb_private_window = 0;
65
66 /* FIXME - These are duplicates after making ecore atoms public */
67
68 Ecore_X_Atom _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM];
69
70 EAPI int ECORE_X_EVENT_ANY = 0;
71 EAPI int ECORE_X_EVENT_MOUSE_IN = 0;
72 EAPI int ECORE_X_EVENT_MOUSE_OUT = 0;
73 EAPI int ECORE_X_EVENT_WINDOW_FOCUS_IN = 0;
74 EAPI int ECORE_X_EVENT_WINDOW_FOCUS_OUT = 0;
75 EAPI int ECORE_X_EVENT_WINDOW_KEYMAP = 0;
76 EAPI int ECORE_X_EVENT_WINDOW_DAMAGE = 0;
77 EAPI int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = 0;
78 EAPI int ECORE_X_EVENT_WINDOW_CREATE = 0;
79 EAPI int ECORE_X_EVENT_WINDOW_DESTROY = 0;
80 EAPI int ECORE_X_EVENT_WINDOW_HIDE = 0;
81 EAPI int ECORE_X_EVENT_WINDOW_SHOW = 0;
82 EAPI int ECORE_X_EVENT_WINDOW_SHOW_REQUEST = 0;
83 EAPI int ECORE_X_EVENT_WINDOW_REPARENT = 0;
84 EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE = 0;
85 EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = 0;
86 EAPI int ECORE_X_EVENT_WINDOW_GRAVITY = 0;
87 EAPI int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = 0;
88 EAPI int ECORE_X_EVENT_WINDOW_STACK = 0;
89 EAPI int ECORE_X_EVENT_WINDOW_STACK_REQUEST = 0;
90 EAPI int ECORE_X_EVENT_WINDOW_PROPERTY = 0;
91 EAPI int ECORE_X_EVENT_WINDOW_COLORMAP = 0;
92 EAPI int ECORE_X_EVENT_WINDOW_MAPPING = 0;
93 EAPI int ECORE_X_EVENT_MAPPING_CHANGE = 0;
94 EAPI int ECORE_X_EVENT_SELECTION_CLEAR = 0;
95 EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0;
96 EAPI int ECORE_X_EVENT_SELECTION_NOTIFY = 0;
97 EAPI int ECORE_X_EVENT_CLIENT_MESSAGE = 0;
98 EAPI int ECORE_X_EVENT_WINDOW_SHAPE = 0;
99 EAPI int ECORE_X_EVENT_SCREENSAVER_NOTIFY = 0;
100 EAPI int ECORE_X_EVENT_SYNC_COUNTER = 0;
101 EAPI int ECORE_X_EVENT_SYNC_ALARM = 0;
102 EAPI int ECORE_X_EVENT_SCREEN_CHANGE = 0;
103 EAPI int ECORE_X_EVENT_DAMAGE_NOTIFY = 0;
104
105 EAPI int ECORE_X_EVENT_WINDOW_DELETE_REQUEST = 0;
106
107 EAPI int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = 0;
108 EAPI int ECORE_X_EVENT_WINDOW_STATE_REQUEST = 0;
109 EAPI int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = 0;
110 EAPI int ECORE_X_EVENT_PING = 0;
111 EAPI int ECORE_X_EVENT_DESKTOP_CHANGE = 0;
112
113 EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = 0;
114 EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = 0;
115 EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = 0;
116
117 EAPI int ECORE_X_MODIFIER_SHIFT = 0;
118 EAPI int ECORE_X_MODIFIER_CTRL = 0;
119 EAPI int ECORE_X_MODIFIER_ALT = 0;
120 EAPI int ECORE_X_MODIFIER_WIN = 0;
121
122 EAPI int ECORE_X_LOCK_SCROLL = 0;
123 EAPI int ECORE_X_LOCK_NUM = 0;
124 EAPI int ECORE_X_LOCK_CAPS = 0;
125
126 /**
127  * @defgroup Ecore_Xcb_Init_Group X Library Init and Shutdown Functions
128  *
129  * Functions that start and shut down the Ecore X Library.
130  */
131
132 /**
133  * Initialize the X display connection to the given display.
134  *
135  * @param   name Display target name.  If @c NULL, the default display is
136  *               assumed.
137  * @return  The number of times the library has been initialized without
138  *          being shut down.  0 is returned if an error occurs.
139  * @ingroup Ecore_Xcb_Init_Group
140  */
141 EAPI int
142 ecore_x_init(const char *name)
143 {
144    xcb_screen_iterator_t iter;
145    int screen;
146    uint32_t max_request_length;
147    const xcb_query_extension_reply_t *reply_big_requests;
148 #ifdef ECORE_XCB_DAMAGE
149    const xcb_query_extension_reply_t *reply_damage;
150 #endif /* ECORE_XCB_DAMAGE */
151 #ifdef ECORE_XCB_COMPOSITE
152    const xcb_query_extension_reply_t *reply_composite;
153 #endif /* ECORE_XCB_COMPOSITE */
154 #ifdef ECORE_XCB_DPMS
155    const xcb_query_extension_reply_t *reply_dpms;
156 #endif /* ECORE_XCB_DPMS */
157 #ifdef ECORE_XCB_RANDR
158    const xcb_query_extension_reply_t *reply_randr;
159 #endif /* ECORE_XCB_RANDR */
160 #ifdef ECORE_XCB_SCREENSAVER
161    const xcb_query_extension_reply_t *reply_screensaver;
162 #endif /* ECORE_XCB_SCREENSAVER */
163 #ifdef ECORE_XCB_SHAPE
164    const xcb_query_extension_reply_t *reply_shape;
165 #endif /* ECORE_XCB_SHAPE */
166 #ifdef ECORE_XCB_SYNC
167    xcb_sync_initialize_cookie_t cookie_sync_init;
168    xcb_sync_initialize_reply_t *reply_sync_init;
169    const xcb_query_extension_reply_t *reply_sync;
170 #endif /* ECORE_XCB_SYNC */
171 #ifdef ECORE_XCB_FIXES
172    const xcb_query_extension_reply_t *reply_xfixes;
173 #endif /* ECORE_XCB_FIXES */
174 #ifdef ECORE_XCB_XINERAMA
175    const xcb_query_extension_reply_t *reply_xinerama;
176 #endif /* ECORE_XCB_XINERAMA */
177 #ifdef ECORE_XCB_XPRINT
178    const xcb_query_extension_reply_t *reply_xprint;
179 #endif /* ECORE_XCB_XPRINT */
180
181    xcb_intern_atom_cookie_t atom_cookies[ECORE_X_ATOMS_COUNT];
182
183    if (++_ecore_xcb_init_count != 1)
184       return _ecore_xcb_init_count;
185
186    /* We init some components (not related to XCB) */
187    if (!eina_init())
188       return --_ecore_xcb_init_count;
189
190    _ecore_x11xcb_log_dom = eina_log_domain_register
191      ("ecore_x", ECORE_XLIB_XCB_DEFAULT_LOG_COLOR);
192    if (_ecore_x11xcb_log_dom < 0)
193      {
194         EINA_LOG_ERR("Impossible to create a log domain the Ecore XCB module.");
195         goto shutdown_eina;
196      }
197
198    if (!ecore_init())
199       goto shutdown_eina;
200    if (!ecore_event_init())
201       goto shutdown_ecore;
202
203    _ecore_xcb_conn = xcb_connect(name, &screen);
204    if (xcb_connection_has_error(_ecore_xcb_conn))
205       goto shutdown_ecore_event;
206
207    /* FIXME: no error code right now */
208    /* _ecore_xcb_error_handler_init(); */
209
210    /********************/
211    /* First round trip */
212    /********************/
213
214    /*
215     * Non blocking stuff:
216     *
217     * 1. We request the atoms
218     * 2. We Prefetch the extension data
219     *
220     */
221
222    /* We request the atoms (non blocking) */
223    _ecore_x_atom_init(atom_cookies);
224
225    /* We prefetch all the extension data (non blocking) */
226
227    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_big_requests_id);
228
229 #ifdef ECORE_XCB_DAMAGE
230    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_damage_id);
231 #endif /* ECORE_XCB_DAMAGE */
232
233 #ifdef ECORE_XCB_COMPOSITE
234    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_composite_id);
235 #endif /* ECORE_XCB_COMPOSITE */
236
237 #ifdef ECORE_XCB_DPMS
238    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_dpms_id);
239 #endif /* ECORE_XCB_DPMS */
240
241 #ifdef ECORE_XCB_RANDR
242    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_randr_id);
243 #endif /* ECORE_XCB_RANDR */
244
245 #ifdef ECORE_XCB_SCREENSAVER
246    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_screensaver_id);
247 #endif /* ECORE_XCB_SCREENSAVER */
248
249 #ifdef ECORE_XCB_SHAPE
250    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shape_id);
251 #endif /* ECORE_XCB_SHAPE */
252
253 #ifdef ECORE_XCB_SYNC
254    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_sync_id);
255    cookie_sync_init = xcb_sync_initialize_unchecked(_ecore_xcb_conn,
256                                                     XCB_SYNC_MAJOR_VERSION,
257                                                     XCB_SYNC_MINOR_VERSION);
258 #endif /* ECORE_XCB_SYNC */
259
260 #ifdef ECORE_XCB_FIXES
261    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xfixes_id);
262 #endif /* ECORE_XCB_FIXES */
263
264 #ifdef ECORE_XCB_XINERAMA
265    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xinerama_id);
266 #endif /* ECORE_XCB_XINERAMA */
267
268 #ifdef ECORE_XCB_XPRINT
269    xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_x_print_id);
270 #endif /* ECORE_XCB_XPRINT */
271
272    _ecore_x_reply_init();
273    _ecore_x_dnd_init();
274    ecore_x_netwm_init();
275    _ecore_x_selection_init();
276
277    /* There is no LASTEvent constant in XCB */
278    /* LASTevent is equal to 35 */
279    _ecore_xcb_event_handlers_num = 35;
280
281    /* We get the default screen */
282    iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
283    for (; iter.rem; --screen, xcb_screen_next (&iter))
284       if (screen == 0)
285         {
286            _ecore_xcb_screen = iter.data;
287            break;
288         }
289
290    /*
291     * Blocking stuff:
292     *
293     * 1. We get the atoms
294     * 2. We ask for the extension data
295     *
296     */
297
298    /* We get the atoms (blocking) */
299    _ecore_x_atom_init_finalize(atom_cookies);
300
301    /* We then ask for the extension data (blocking) */
302    reply_big_requests = xcb_get_extension_data(_ecore_xcb_conn, &xcb_big_requests_id);
303
304 #ifdef ECORE_XCB_DAMAGE
305    reply_damage = xcb_get_extension_data(_ecore_xcb_conn, &xcb_damage_id);
306    if (reply_damage)
307       _ecore_xcb_event_damage_id = reply_damage->first_event + XCB_DAMAGE_NOTIFY;
308
309    if (_ecore_xcb_event_damage_id >= _ecore_xcb_event_handlers_num)
310       _ecore_xcb_event_handlers_num = _ecore_xcb_event_damage_id + 1;
311
312 #endif /* ECORE_XCB_DAMAGE */
313
314 #ifdef ECORE_XCB_COMPOSITE
315    reply_composite = xcb_get_extension_data(_ecore_xcb_conn, &xcb_composite_id);
316 #endif /* ECORE_XCB_COMPOSITE */
317
318 #ifdef ECORE_XCB_DPMS
319    reply_dpms = xcb_get_extension_data(_ecore_xcb_conn, &xcb_dpms_id);
320 #endif /* ECORE_XCB_DPMS */
321
322 #ifdef ECORE_XCB_RANDR
323    reply_randr = xcb_get_extension_data(_ecore_xcb_conn, &xcb_randr_id);
324    if (reply_randr)
325       _ecore_xcb_event_randr_id = reply_randr->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
326
327    if (_ecore_xcb_event_randr_id >= _ecore_xcb_event_handlers_num)
328       _ecore_xcb_event_handlers_num = _ecore_xcb_event_randr_id + 1;
329
330 #endif /* ECORE_XCB_RANDR */
331
332 #ifdef ECORE_XCB_SCREENSAVER
333    reply_screensaver = xcb_get_extension_data(_ecore_xcb_conn, &xcb_screensaver_id);
334    if (reply_screensaver)
335       _ecore_xcb_event_screensaver_id = reply_screensaver->first_event + XCB_SCREENSAVER_NOTIFY;
336
337    if (_ecore_xcb_event_screensaver_id >= _ecore_xcb_event_handlers_num)
338       _ecore_xcb_event_handlers_num = _ecore_xcb_event_screensaver_id + 1;
339
340 #endif /* ECORE_XCB_SCREENSAVER */
341
342 #ifdef ECORE_XCB_SHAPE
343    reply_shape = xcb_get_extension_data(_ecore_xcb_conn, &xcb_shape_id);
344    if (reply_shape)
345       _ecore_xcb_event_shape_id = reply_shape->first_event + XCB_SHAPE_NOTIFY;
346
347    if (_ecore_xcb_event_shape_id >= _ecore_xcb_event_handlers_num)
348       _ecore_xcb_event_handlers_num = _ecore_xcb_event_shape_id + 1;
349
350 #endif /* ECORE_XCB_SHAPE */
351
352 #ifdef ECORE_XCB_SYNC
353    reply_sync = xcb_get_extension_data(_ecore_xcb_conn, &xcb_sync_id);
354    if (reply_sync)
355      {
356         _ecore_xcb_event_sync_id = reply_sync->first_event;
357         reply_sync_init = xcb_sync_initialize_reply(_ecore_xcb_conn,
358                                                     cookie_sync_init, NULL);
359         if (!reply_sync_init)
360            _ecore_xcb_event_sync_id = 0;
361         else
362            free(reply_sync_init);
363      }
364
365    if (_ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY >= _ecore_xcb_event_handlers_num)
366       _ecore_xcb_event_handlers_num = _ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY + 1;
367
368 #endif /* ECORE_XCB_SYNC */
369
370 #ifdef ECORE_XCB_FIXES
371    reply_xfixes = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xfixes_id);
372    if (reply_xfixes)
373       _ecore_xcb_event_fixes_selection_id = reply_xfixes->first_event + XCB_XFIXES_SELECTION_NOTIFY;
374
375    if (_ecore_xcb_event_fixes_selection_id >= _ecore_xcb_event_handlers_num)
376       _ecore_xcb_event_handlers_num = _ecore_xcb_event_fixes_selection_id + 1;
377
378 #endif /* ECORE_XCB_FIXES */
379
380 #ifdef ECORE_XCB_XINERAMA
381    reply_xinerama = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xinerama_id);
382 #endif /* ECORE_XCB_XINERAMA */
383
384 #ifdef ECORE_XCB_XPRINT
385    reply_xprint = xcb_get_extension_data(_ecore_xcb_conn, &xcb_x_print_id);
386 #endif /* ECORE_XCB_XPRINT */
387
388    /*********************/
389    /* Second round trip */
390    /*********************/
391
392    /* We ask for the QueryVersion request of the extensions */
393 #ifdef ECORE_XCB_DAMAGE
394    _ecore_x_damage_init(reply_damage);
395 #endif /* ECORE_XCB_DAMAGE */
396 #ifdef ECORE_XCB_COMPOSITE
397    _ecore_x_composite_init(reply_composite);
398 #endif /* ECORE_XCB_COMPOSITE */
399 #ifdef ECORE_XCB_DPMS
400    _ecore_x_dpms_init(reply_dpms);
401 #endif /* ECORE_XCB_DPMS */
402 #ifdef ECORE_XCB_RANDR
403    _ecore_x_randr_init(reply_randr);
404 #endif /* ECORE_XCB_RANDR */
405 #ifdef ECORE_XCB_SCREENSAVER
406    _ecore_x_screensaver_init(reply_screensaver);
407 #endif /* ECORE_XCB_SCREENSAVER */
408 #ifdef ECORE_XCB_SHAPE
409    _ecore_x_shape_init(reply_shape);
410 #endif /* ECORE_XCB_SHAPE */
411 #ifdef ECORE_XCB_SYNC
412    _ecore_x_sync_init(reply_sync);
413 #endif /* ECORE_XCB_SYNC */
414 #ifdef ECORE_XCB_FIXES
415    _ecore_x_xfixes_init(reply_xfixes);
416 #endif /* ECORE_XCB_FIXES */
417 #ifdef ECORE_XCB_XINERAMA
418    _ecore_x_xinerama_init(reply_xinerama);
419 #endif /* ECORE_XCB_XINERAMA */
420
421    /* we enable the Big Request extension if present */
422    max_request_length = xcb_get_maximum_request_length(_ecore_xcb_conn);
423
424    _ecore_xcb_event_handlers = calloc(_ecore_xcb_event_handlers_num, sizeof(void *));
425    if (!_ecore_xcb_event_handlers)
426       goto finalize_extensions;
427
428 #ifdef ECORE_XCB_CURSOR
429    _ecore_xcb_xcursor = XcursorSupportsARGB(_ecore_xcb_conn);
430 #endif /* ECORE_XCB_CURSOR */
431
432    _ecore_xcb_event_handlers[XCB_EVENT_ANY] = _ecore_x_event_handle_any_event;
433    _ecore_xcb_event_handlers[XCB_KEY_PRESS] = _ecore_x_event_handle_key_press;
434    _ecore_xcb_event_handlers[XCB_KEY_RELEASE] = _ecore_x_event_handle_key_release;
435    _ecore_xcb_event_handlers[XCB_BUTTON_PRESS] = _ecore_x_event_handle_button_press;
436    _ecore_xcb_event_handlers[XCB_BUTTON_RELEASE] = _ecore_x_event_handle_button_release;
437    _ecore_xcb_event_handlers[XCB_MOTION_NOTIFY] = _ecore_x_event_handle_motion_notify;
438    _ecore_xcb_event_handlers[XCB_ENTER_NOTIFY] = _ecore_x_event_handle_enter_notify;
439    _ecore_xcb_event_handlers[XCB_LEAVE_NOTIFY] = _ecore_x_event_handle_leave_notify;
440    _ecore_xcb_event_handlers[XCB_FOCUS_IN] = _ecore_x_event_handle_focus_in;
441    _ecore_xcb_event_handlers[XCB_FOCUS_OUT] = _ecore_x_event_handle_focus_out;
442    _ecore_xcb_event_handlers[XCB_KEYMAP_NOTIFY] = _ecore_x_event_handle_keymap_notify;
443    _ecore_xcb_event_handlers[XCB_EXPOSE] = _ecore_x_event_handle_expose;
444    _ecore_xcb_event_handlers[XCB_GRAPHICS_EXPOSURE] = _ecore_x_event_handle_graphics_expose;
445    _ecore_xcb_event_handlers[XCB_VISIBILITY_NOTIFY] = _ecore_x_event_handle_visibility_notify;
446    _ecore_xcb_event_handlers[XCB_CREATE_NOTIFY] = _ecore_x_event_handle_create_notify;
447    _ecore_xcb_event_handlers[XCB_DESTROY_NOTIFY] = _ecore_x_event_handle_destroy_notify;
448    _ecore_xcb_event_handlers[XCB_UNMAP_NOTIFY] = _ecore_x_event_handle_unmap_notify;
449    _ecore_xcb_event_handlers[XCB_MAP_NOTIFY] = _ecore_x_event_handle_map_notify;
450    _ecore_xcb_event_handlers[XCB_MAP_REQUEST] = _ecore_x_event_handle_map_request;
451    _ecore_xcb_event_handlers[XCB_REPARENT_NOTIFY] = _ecore_x_event_handle_reparent_notify;
452    _ecore_xcb_event_handlers[XCB_CONFIGURE_NOTIFY] = _ecore_x_event_handle_configure_notify;
453    _ecore_xcb_event_handlers[XCB_CONFIGURE_REQUEST] = _ecore_x_event_handle_configure_request;
454    _ecore_xcb_event_handlers[XCB_GRAVITY_NOTIFY] = _ecore_x_event_handle_gravity_notify;
455    _ecore_xcb_event_handlers[XCB_RESIZE_REQUEST] = _ecore_x_event_handle_resize_request;
456    _ecore_xcb_event_handlers[XCB_CIRCULATE_NOTIFY] = _ecore_x_event_handle_circulate_notify;
457    _ecore_xcb_event_handlers[XCB_CIRCULATE_REQUEST] = _ecore_x_event_handle_circulate_request;
458    _ecore_xcb_event_handlers[XCB_PROPERTY_NOTIFY] = _ecore_x_event_handle_property_notify;
459    _ecore_xcb_event_handlers[XCB_SELECTION_CLEAR] = _ecore_x_event_handle_selection_clear;
460    _ecore_xcb_event_handlers[XCB_SELECTION_REQUEST] = _ecore_x_event_handle_selection_request;
461    _ecore_xcb_event_handlers[XCB_SELECTION_NOTIFY] = _ecore_x_event_handle_selection_notify;
462    _ecore_xcb_event_handlers[XCB_COLORMAP_NOTIFY] = _ecore_x_event_handle_colormap_notify;
463    _ecore_xcb_event_handlers[XCB_CLIENT_MESSAGE] = _ecore_x_event_handle_client_message;
464    _ecore_xcb_event_handlers[XCB_MAPPING_NOTIFY] = _ecore_x_event_handle_mapping_notify;
465 #ifdef ECORE_XCB_DAMAGE
466    if (_ecore_xcb_event_damage_id)
467       _ecore_xcb_event_handlers[_ecore_xcb_event_damage_id] = _ecore_x_event_handle_damage_notify;
468
469 #endif /* ECORE_XCB_DAMAGE */
470 #ifdef ECORE_XCB_RANDR
471    if (_ecore_xcb_event_randr_id)
472       _ecore_xcb_event_handlers[_ecore_xcb_event_randr_id] = _ecore_x_event_handle_randr_change;
473
474 #endif /* ECORE_XCB_RANDR */
475 #ifdef ECORE_XCB_SCREENSAVER
476    if (_ecore_xcb_event_screensaver_id)
477       _ecore_xcb_event_handlers[_ecore_xcb_event_screensaver_id] = _ecore_x_event_handle_screensaver_notify;
478
479 #endif /* ECORE_XCB_SCREENSAVER */
480 #ifdef ECORE_XCB_SHAPE
481    if (_ecore_xcb_event_shape_id)
482       _ecore_xcb_event_handlers[_ecore_xcb_event_shape_id] = _ecore_x_event_handle_shape_change;
483
484 #endif /* ECORE_XCB_SHAPE */
485 #ifdef ECORE_XCB_SYNC
486    if (_ecore_xcb_event_sync_id)
487      {
488         _ecore_xcb_event_handlers[_ecore_xcb_event_sync_id + XCB_SYNC_COUNTER_NOTIFY] =
489            _ecore_x_event_handle_sync_counter;
490         _ecore_xcb_event_handlers[_ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY] =
491            _ecore_x_event_handle_sync_alarm;
492      }
493
494 #endif /* ECORE_XCB_SYNC */
495 #ifdef ECORE_XCB_FIXES
496    if (_ecore_xcb_event_fixes_selection_id)
497       _ecore_xcb_event_handlers[_ecore_xcb_event_fixes_selection_id] = _ecore_x_event_handle_fixes_selection_notify;
498
499 #endif /* ECORE_XCB_FIXES */
500
501    if (!ECORE_X_EVENT_ANY)
502      {
503         ECORE_X_EVENT_ANY = ecore_event_type_new();
504         ECORE_X_EVENT_MOUSE_IN = ecore_event_type_new();
505         ECORE_X_EVENT_MOUSE_OUT = ecore_event_type_new();
506         ECORE_X_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new();
507         ECORE_X_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new();
508         ECORE_X_EVENT_WINDOW_KEYMAP = ecore_event_type_new();
509         ECORE_X_EVENT_WINDOW_DAMAGE = ecore_event_type_new();
510         ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = ecore_event_type_new();
511         ECORE_X_EVENT_WINDOW_CREATE = ecore_event_type_new();
512         ECORE_X_EVENT_WINDOW_DESTROY = ecore_event_type_new();
513         ECORE_X_EVENT_WINDOW_HIDE = ecore_event_type_new();
514         ECORE_X_EVENT_WINDOW_SHOW = ecore_event_type_new();
515         ECORE_X_EVENT_WINDOW_SHOW_REQUEST = ecore_event_type_new();
516         ECORE_X_EVENT_WINDOW_REPARENT = ecore_event_type_new();
517         ECORE_X_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
518         ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = ecore_event_type_new();
519         ECORE_X_EVENT_WINDOW_GRAVITY = ecore_event_type_new();
520         ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = ecore_event_type_new();
521         ECORE_X_EVENT_WINDOW_STACK = ecore_event_type_new();
522         ECORE_X_EVENT_WINDOW_STACK_REQUEST = ecore_event_type_new();
523         ECORE_X_EVENT_WINDOW_PROPERTY = ecore_event_type_new();
524         ECORE_X_EVENT_WINDOW_COLORMAP = ecore_event_type_new();
525         ECORE_X_EVENT_WINDOW_MAPPING = ecore_event_type_new();
526         ECORE_X_EVENT_MAPPING_CHANGE = ecore_event_type_new();
527         ECORE_X_EVENT_SELECTION_CLEAR = ecore_event_type_new();
528         ECORE_X_EVENT_SELECTION_REQUEST = ecore_event_type_new();
529         ECORE_X_EVENT_SELECTION_NOTIFY = ecore_event_type_new();
530         ECORE_X_EVENT_CLIENT_MESSAGE = ecore_event_type_new();
531         ECORE_X_EVENT_WINDOW_SHAPE = ecore_event_type_new();
532         ECORE_X_EVENT_SCREENSAVER_NOTIFY = ecore_event_type_new();
533         ECORE_X_EVENT_SYNC_COUNTER = ecore_event_type_new();
534         ECORE_X_EVENT_SYNC_ALARM = ecore_event_type_new();
535         ECORE_X_EVENT_SCREEN_CHANGE = ecore_event_type_new();
536         ECORE_X_EVENT_DAMAGE_NOTIFY = ecore_event_type_new();
537
538         ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
539         ECORE_X_EVENT_DESKTOP_CHANGE = ecore_event_type_new();
540         ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = ecore_event_type_new();
541         ECORE_X_EVENT_WINDOW_STATE_REQUEST = ecore_event_type_new();
542         ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = ecore_event_type_new();
543         ECORE_X_EVENT_PING = ecore_event_type_new();
544
545         ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = ecore_event_type_new();
546         ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = ecore_event_type_new();
547         ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = ecore_event_type_new();
548      }
549
550    /* everything has these... unless its like a pda... :) */
551    ECORE_X_MODIFIER_SHIFT = _ecore_xcb_key_mask_get(XK_Shift_L);
552    ECORE_X_MODIFIER_CTRL = _ecore_xcb_key_mask_get(XK_Control_L);
553
554    /* apple's xdarwin has no alt!!!! */
555    ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Alt_L);
556    if (!ECORE_X_MODIFIER_ALT)
557       ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Meta_L);
558
559    if (!ECORE_X_MODIFIER_ALT)
560       ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Super_L);
561
562    /* the windows key... a valid modifier :) */
563    ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Super_L);
564    if (!ECORE_X_MODIFIER_WIN)
565       ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Mode_switch);
566
567    if (!ECORE_X_MODIFIER_WIN)
568       ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Meta_L);
569
570    if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT)
571       ECORE_X_MODIFIER_WIN = 0;
572
573    if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL)
574       ECORE_X_MODIFIER_ALT = 0;
575
576    ECORE_X_LOCK_SCROLL = _ecore_xcb_key_mask_get(XK_Scroll_Lock);
577    ECORE_X_LOCK_NUM = _ecore_xcb_key_mask_get(XK_Num_Lock);
578    ECORE_X_LOCK_CAPS = _ecore_xcb_key_mask_get(XK_Caps_Lock);
579
580    _ecore_xcb_fd_handler_handle =
581       ecore_main_fd_handler_add(xcb_get_file_descriptor(_ecore_xcb_conn),
582                                 ECORE_FD_READ,
583                                 _ecore_xcb_fd_handler, _ecore_xcb_conn,
584                                 _ecore_xcb_fd_handler_buf, _ecore_xcb_conn);
585    if (!_ecore_xcb_fd_handler_handle)
586       goto free_event_handlers;
587
588    _ecore_xcb_filter_handler = ecore_event_filter_add(_ecore_xcb_event_filter_start, _ecore_xcb_event_filter_filter, _ecore_xcb_event_filter_end, NULL);
589
590    /* This is just to be anal about naming conventions */
591
592    _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] = ECORE_X_ATOM_WM_DELETE_WINDOW;
593    _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] = ECORE_X_ATOM_WM_TAKE_FOCUS;
594    _ecore_xcb_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_PING] = ECORE_X_ATOM_NET_WM_PING;
595    _ecore_xcb_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
596
597    _ecore_xcb_init_count++;
598
599    _ecore_xcb_private_window = ecore_x_window_override_new(0, -77, -777, 123, 456);
600
601    /* We finally get the replies of the QueryVersion request */
602 #ifdef ECORE_XCB_DAMAGE
603    _ecore_x_damage_init_finalize();
604 #endif /* ECORE_XCB_DAMAGE */
605 #ifdef ECORE_XCB_COMPOSITE
606    _ecore_x_composite_init_finalize();
607 #endif /* ECORE_XCB_COMPOSITE */
608 #ifdef ECORE_XCB_DPMS
609    _ecore_x_dpms_init_finalize();
610 #endif /* ECORE_XCB_DPMS */
611 #ifdef ECORE_XCB_RANDR
612    _ecore_x_randr_init_finalize();
613 #endif /* ECORE_XCB_RANDR */
614 #ifdef ECORE_XCB_SCREENSAVER
615    _ecore_x_screensaver_init_finalize();
616 #endif /* ECORE_XCB_SCREENSAVER */
617 #ifdef ECORE_XCB_SHAPE
618    _ecore_x_shape_init_finalize();
619 #endif /* ECORE_XCB_SHAPE */
620 #ifdef ECORE_XCB_SYNC
621    _ecore_x_sync_init_finalize();
622 #endif /* ECORE_XCB_SYNC */
623 #ifdef ECORE_XCB_FIXES
624    _ecore_x_xfixes_init_finalize();
625 #endif /* ECORE_XCB_FIXES */
626 #ifdef ECORE_XCB_XINERAMA
627    _ecore_x_xinerama_init_finalize();
628 #endif /* ECORE_XCB_XINERAMA */
629
630    return _ecore_xcb_init_count;
631
632 free_event_handlers:
633    free(_ecore_xcb_event_handlers);
634    _ecore_xcb_event_handlers = NULL;
635 finalize_extensions:
636    /* We get the replies of the QueryVersion request because we leave */
637 #ifdef ECORE_XCB_DAMAGE
638    _ecore_x_damage_init_finalize();
639 #endif /* ECORE_XCB_DAMAGE */
640 #ifdef ECORE_XCB_COMPOSITE
641    _ecore_x_composite_init_finalize();
642 #endif /* ECORE_XCB_COMPOSITE */
643 #ifdef ECORE_XCB_DPMS
644    _ecore_x_dpms_init_finalize();
645 #endif /* ECORE_XCB_DPMS */
646 #ifdef ECORE_XCB_RANDR
647    _ecore_x_randr_init_finalize();
648 #endif /* ECORE_XCB_RANDR */
649 #ifdef ECORE_XCB_SCREENSAVER
650    _ecore_x_screensaver_init_finalize();
651 #endif /* ECORE_XCB_SCREENSAVER */
652 #ifdef ECORE_XCB_SHAPE
653    _ecore_x_shape_init_finalize();
654 #endif /* ECORE_XCB_SHAPE */
655 #ifdef ECORE_XCB_SYNC
656    _ecore_x_sync_init_finalize();
657 #endif /* ECORE_XCB_SYNC */
658 #ifdef ECORE_XCB_FIXES
659    _ecore_x_xfixes_init_finalize();
660 #endif /* ECORE_XCB_FIXES */
661 #ifdef ECORE_XCB_XINERAMA
662    _ecore_x_xinerama_init_finalize();
663 #endif /* ECORE_XCB_XINERAMA */
664 shutdown_ecore_event:
665    ecore_event_shutdown();
666 shutdown_ecore:
667    ecore_shutdown();
668 shutdown_eina:
669    eina_log_domain_unregister(_ecore_x11xcb_log_dom);
670    _ecore_x11xcb_log_dom = -1;
671    eina_shutdown();
672
673    return --_ecore_xcb_init_count;
674 } /* ecore_x_init */
675
676 static int
677 _ecore_x_shutdown(int close_display)
678 {
679    if (--_ecore_xcb_init_count != 0)
680       return _ecore_xcb_init_count;
681
682    if (!_ecore_xcb_conn)
683       return _ecore_xcb_init_count;
684
685    ecore_main_fd_handler_del(_ecore_xcb_fd_handler_handle);
686    if (close_display)
687       xcb_disconnect(_ecore_xcb_conn);
688    else
689       close(xcb_get_file_descriptor(_ecore_xcb_conn));
690
691    free(_ecore_xcb_event_handlers);
692    ecore_event_filter_del(_ecore_xcb_filter_handler);
693    _ecore_xcb_fd_handler_handle = NULL;
694    _ecore_xcb_filter_handler = NULL;
695    _ecore_xcb_conn = NULL;
696    _ecore_xcb_event_handlers = NULL;
697    _ecore_x_selection_shutdown();
698    _ecore_x_dnd_shutdown();
699    ecore_x_netwm_shutdown();
700    _ecore_x_reply_shutdown();
701
702    ecore_event_shutdown();
703    ecore_shutdown();
704
705    eina_log_domain_unregister(_ecore_x11xcb_log_dom);
706    _ecore_x11xcb_log_dom = -1;
707    eina_shutdown();
708
709    return _ecore_xcb_init_count;
710 } /* _ecore_x_shutdown */
711
712 /**
713  * Shuts down the Ecore X library.
714  *
715  * In shutting down the library, the X display connection is terminated
716  * and any event handlers for it are removed.
717  *
718  * @return  The number of times the library has been initialized without
719  *          being shut down.
720  * @ingroup Ecore_Xcb_Init_Group
721  */
722 EAPI int
723 ecore_x_shutdown(void)
724 {
725    return _ecore_x_shutdown(1);
726 } /* ecore_x_shutdown */
727
728 /**
729  * Shuts down the Ecore X library.
730  *
731  * As ecore_xcb_shutdown, except do not close Display, only connection.
732  *
733  * @ingroup Ecore_Xcb_Init_Group
734  */
735 EAPI int
736 ecore_x_disconnect(void)
737 {
738    return _ecore_x_shutdown(0);
739 } /* ecore_x_disconnect */
740
741 /**
742  * @defgroup Ecore_Xcb_Display_Attr_Group X Display Attributes
743  *
744  * Functions that set and retrieve X display attributes.
745  */
746
747 EAPI Ecore_X_Display *
748 ecore_x_display_get(void)
749 {
750    return NULL;
751 } /* ecore_x_display_get */
752
753 /**
754  * Retrieves the Ecore_X_Connection handle used for the current X connection.
755  * @return  The current X connection.
756  * @ingroup Ecore_Xcb_Display_Attr_Group
757  */
758 EAPI Ecore_X_Connection *
759 ecore_x_connection_get(void)
760 {
761    return (Ecore_X_Connection *)_ecore_xcb_conn;
762 } /* ecore_x_connection_get */
763
764 /**
765  * Retrieves the X display file descriptor.
766  * @return  The current X display file descriptor.
767  * @ingroup Ecore_Xcb_Display_Attr_Group
768  */
769 EAPI int
770 ecore_x_fd_get(void)
771 {
772    return xcb_get_file_descriptor(_ecore_xcb_conn);
773 } /* ecore_x_fd_get */
774
775 /**
776  * Retrieves the Ecore_X_Screen handle used for the current X connection.
777  * @return  The current default screen.
778  * @ingroup Ecore_Xcb_Display_Attr_Group
779  */
780 EAPI Ecore_X_Screen *
781 ecore_x_default_screen_get(void)
782 {
783    return (Ecore_X_Screen *)_ecore_xcb_screen;
784 } /* ecore_x_default_screen_get */
785
786 /**
787  * Retrieves the size of an Ecore_X_Screen.
788  * @param screen the handle to the screen to query.
789  * @param w where to return the width. May be NULL. Returns 0 on errors.
790  * @param h where to return the height. May be NULL. Returns 0 on errors.
791  * @ingroup Ecore_X_Display_Attr_Group
792  * @see ecore_x_default_screen_get()
793  *
794  * @since 1.1
795  */
796 EAPI void
797 ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h)
798 {
799    xcb_screen_t *s = (xcb_screen_t *)screen;
800    LOGFN(__FILE__, __LINE__, __FUNCTION__);
801    if (w) *w = 0;
802    if (h) *h = 0;
803    if (!s) return;
804    if (w) *w = s->width_in_pixels;
805    if (h) *h = s->height_in_pixels;
806 }
807
808 /**
809  * Sets the timeout for a double and triple clicks to be flagged.
810  *
811  * This sets the time between clicks before the double_click flag is
812  * set in a button down event. If 3 clicks occur within double this
813  * time, the triple_click flag is also set.
814  *
815  * @param   t The time in seconds
816  * @ingroup Ecore_Xcb_Display_Attr_Group
817  */
818 EAPI void
819 ecore_x_double_click_time_set(double t)
820 {
821    if (t < 0.0)
822       t = 0.0;
823
824    _ecore_xcb_double_click_time = t;
825 } /* ecore_x_double_click_time_set */
826
827 /**
828  * Retrieves the double and triple click flag timeout.
829  *
830  * See @ref ecore_xcb_double_click_time_set for more information.
831  *
832  * @return  The timeout for double clicks in seconds.
833  * @ingroup Ecore_Xcb_Display_Attr_Group
834  */
835 EAPI double
836 ecore_x_double_click_time_get(void)
837 {
838    return _ecore_xcb_double_click_time;
839 } /* ecore_x_double_click_time_get */
840
841 /**
842  * @defgroup Ecore_Xcb_Flush_Group X Synchronization Functions
843  *
844  * Functions that ensure that all commands that have been issued by the
845  * Ecore X library have been sent to the server.
846  */
847
848 /**
849  * Sends all X commands in the X Display buffer.
850  * @ingroup Ecore_Xcb_Flush_Group
851  */
852 EAPI void
853 ecore_x_flush(void)
854 {
855    xcb_flush(_ecore_xcb_conn);
856 } /* ecore_x_flush */
857
858 /**
859  * Flushes the command buffer and waits until all requests have been
860  * processed by the server.
861  * @ingroup Ecore_Xcb_Flush_Group
862  */
863 EAPI void
864 ecore_x_sync(void)
865 {
866    free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), NULL));
867 } /* ecore_x_sync */
868
869 /**
870  * Kill all clients with subwindows under a given window.
871  *
872  * You can kill all clients connected to the X server by using
873  * @ref ecore_x_window_root_list to get a list of root windows, and
874  * then passing each root window to this function.
875  *
876  * @param root The window whose children will be killed.
877  */
878 EAPI void
879 ecore_x_killall(Ecore_X_Window root)
880 {
881    int screens;
882    int i;
883
884    xcb_grab_server(_ecore_xcb_conn);
885    screens = xcb_setup_roots_iterator (xcb_get_setup (_ecore_xcb_conn)).rem;
886
887    /* Tranverse window tree starting from root, and drag each
888     * before the firing squad */
889    for (i = 0; i < screens; ++i)
890      {
891         xcb_query_tree_cookie_t cookie;
892         xcb_query_tree_reply_t *reply;
893
894         cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, root);
895         reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
896         if (reply)
897           {
898              xcb_window_t *wins = NULL;
899              int tree_c_len;
900              int i;
901
902              wins = xcb_query_tree_children(reply);
903              tree_c_len = xcb_query_tree_children_length(reply);
904              for (i = 0; i < tree_c_len; i++)
905                 xcb_kill_client(_ecore_xcb_conn, wins[i]);
906              free(reply);
907           }
908      }
909
910    xcb_ungrab_server(_ecore_xcb_conn);
911    free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), NULL));
912 } /* ecore_x_killall */
913
914 /**
915  * Kill a specific client
916  *
917  * You can kill a specific client woning window @p window
918  *
919  * @param window Window of the client to be killed
920  */
921 EAPI void
922 ecore_x_kill(Ecore_X_Window window)
923 {
924    xcb_kill_client(_ecore_xcb_conn, window);
925 } /* ecore_x_kill */
926
927 /**
928  * TODO: Invoke the standard system beep to alert users
929  */
930 EAPI Eina_Bool
931 ecore_x_bell(int percent)
932 {
933    return 0;
934 } /* ecore_x_bell */
935
936 /**
937  * Return the last event time
938  */
939 EAPI Ecore_X_Time
940 ecore_x_current_time_get(void)
941 {
942    return _ecore_xcb_event_last_time;
943 } /* ecore_x_current_time_get */
944
945 static void
946 handle_event(xcb_generic_event_t *ev)
947 {
948    uint8_t response_type = ev->response_type & ~0x80;
949
950    if (response_type < _ecore_xcb_event_handlers_num)
951      {
952         if (_ecore_xcb_event_handlers[XCB_EVENT_ANY])
953            _ecore_xcb_event_handlers[XCB_EVENT_ANY] (ev);
954
955         if (_ecore_xcb_event_handlers[response_type])
956            _ecore_xcb_event_handlers[response_type] (ev);
957      }
958 } /* handle_event */
959
960 static Eina_Bool
961 _ecore_xcb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
962 {
963    xcb_connection_t *c;
964    xcb_generic_event_t *ev;
965
966    c = (xcb_connection_t *)data;
967
968 /*    INF ("nbr events: %d", _ecore_xcb_event_handlers_num); */
969
970    /* We check if _ecore_xcb_event_buffered is NULL or not */
971    if (_ecore_xcb_event_buffered)
972      {
973         handle_event(_ecore_xcb_event_buffered);
974         _ecore_xcb_event_buffered = NULL;
975      }
976
977    while ((ev = xcb_poll_for_event(c)))
978       handle_event(ev);
979
980    return ECORE_CALLBACK_RENEW;
981 } /* _ecore_xcb_fd_handler */
982
983 static Eina_Bool
984 _ecore_xcb_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
985 {
986    xcb_connection_t *c;
987
988    c = (xcb_connection_t *)data;
989
990    _ecore_xcb_event_buffered = xcb_poll_for_event(c);
991    if (!_ecore_xcb_event_buffered)
992       return ECORE_CALLBACK_CANCEL;
993
994    return ECORE_CALLBACK_RENEW;
995 } /* _ecore_xcb_fd_handler_buf */
996
997 /* FIXME: possible roundtrip */
998 /* FIXME: fix xcb_keysyms. It's ugly !! (reply in xcb_key_symbols_get_keysym) */
999 static int
1000 _ecore_xcb_key_mask_get(xcb_keysym_t sym)
1001 {
1002    xcb_get_modifier_mapping_cookie_t cookie;
1003    xcb_get_modifier_mapping_reply_t *reply;
1004    xcb_key_symbols_t *symbols;
1005    xcb_keysym_t sym2;
1006    int i, j;
1007    xcb_keycode_t *keycodes = NULL;
1008    int mod_keys_len;
1009    const int masks[8] =
1010    {
1011       XCB_MOD_MASK_SHIFT,
1012       XCB_MOD_MASK_LOCK,
1013       XCB_MOD_MASK_CONTROL,
1014       XCB_MOD_MASK_1,
1015       XCB_MOD_MASK_2,
1016       XCB_MOD_MASK_3,
1017       XCB_MOD_MASK_4,
1018       XCB_MOD_MASK_5
1019    };
1020
1021    cookie = xcb_get_modifier_mapping_unchecked(_ecore_xcb_conn);
1022    symbols = xcb_key_symbols_alloc(_ecore_xcb_conn);
1023
1024    reply = xcb_get_modifier_mapping_reply(_ecore_xcb_conn, cookie, NULL);
1025    if (!reply)
1026      {
1027         xcb_key_symbols_free(symbols);
1028
1029         return 0;
1030      }
1031
1032    keycodes = xcb_get_modifier_mapping_keycodes(reply);
1033    mod_keys_len = xcb_get_modifier_mapping_keycodes_length(reply);
1034    for (i = 0; i < mod_keys_len; i++)
1035      {
1036         for (j = 0; j < 8; j++)
1037           {
1038              sym2 = xcb_key_symbols_get_keysym(symbols, keycodes[i], j);
1039              if (sym2 != 0)
1040                 break;
1041           }
1042         if (sym2 == sym)
1043           {
1044              int mask;
1045
1046              mask = masks[j];
1047              free(reply);
1048              xcb_key_symbols_free(symbols);
1049              return mask;
1050           }
1051      }
1052
1053    free(reply);
1054    xcb_key_symbols_free(symbols);
1055
1056    return 0;
1057 } /* _ecore_xcb_key_mask_get */
1058
1059 typedef struct _Ecore_X_Filter_Data   Ecore_X_Filter_Data;
1060
1061 struct _Ecore_X_Filter_Data
1062 {
1063    int last_event_type;
1064 };
1065
1066 static void *
1067 _ecore_xcb_event_filter_start(void *data __UNUSED__)
1068 {
1069    Ecore_X_Filter_Data *filter_data;
1070
1071    filter_data = calloc(1, sizeof(Ecore_X_Filter_Data));
1072    return filter_data;
1073 } /* _ecore_xcb_event_filter_start */
1074
1075 static Eina_Bool
1076 _ecore_xcb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__)
1077 {
1078    Ecore_X_Filter_Data *filter_data;
1079
1080    filter_data = loop_data;
1081    if (!filter_data)
1082       return EINA_TRUE;
1083
1084    if (type == ECORE_EVENT_MOUSE_MOVE)
1085      {
1086         if ((filter_data->last_event_type) == ECORE_EVENT_MOUSE_MOVE)
1087           {
1088              filter_data->last_event_type = type;
1089              return EINA_FALSE;
1090           }
1091      }
1092
1093    filter_data->last_event_type = type;
1094    return EINA_TRUE;
1095 } /* _ecore_xcb_event_filter_filter */
1096
1097 static void
1098 _ecore_xcb_event_filter_end(void *data __UNUSED__, void *loop_data)
1099 {
1100    Ecore_X_Filter_Data *filter_data;
1101
1102    filter_data = loop_data;
1103    if (filter_data)
1104       free(filter_data);
1105 } /* _ecore_xcb_event_filter_end */
1106
1107 /*****************************************************************************/
1108 /*****************************************************************************/
1109 /*****************************************************************************/
1110 /* FIXME: these funcs need categorising */
1111 /*****************************************************************************/
1112
1113 /**
1114  * Get a list of all the root windows on the server.
1115  *
1116  * @note   The returned array will need to be freed after use.
1117  * @param  num_ret Pointer to integer to put number of windows returned in.
1118  * @return An array of all the root windows.  @c NULL is returned if memory
1119  *         could not be allocated for the list, or if @p num_ret is @c NULL.
1120  */
1121 EAPI Ecore_X_Window *
1122 ecore_x_window_root_list(int *num_ret)
1123 {
1124    xcb_screen_iterator_t iter;
1125    const xcb_setup_t *setup;
1126    uint8_t i;
1127    uint8_t num;
1128    Ecore_X_Window *roots;
1129 /* #ifdef ECORE_XCBXPRINT */
1130 /*    int xp_base, xp_err_base; */
1131 /* #endif /\* ECORE_XCBXPRINT *\/ */
1132
1133    if (!num_ret)
1134       return NULL;
1135
1136    *num_ret = 0;
1137
1138    /* FIXME: todo... */
1139 /* #ifdef ECORE_XCBXPRINT */
1140 /*    num = ScreenCount(_ecore_xcb_conn); */
1141 /*    if (ecore_xcb_xprint_query()) */
1142 /*      { */
1143 /*      Screen **ps = NULL; */
1144 /*      int psnum = 0; */
1145
1146 /*      ps = XpQueryScreens(_ecore_xcb_conn, &psnum); */
1147 /*      if (ps) */
1148 /*        { */
1149 /*           int overlap, j; */
1150
1151 /*           overlap = 0; */
1152 /*           for (i = 0; i < num; i++) */
1153 /*             { */
1154 /*                for (j = 0; j < psnum; j++) */
1155 /*                  { */
1156 /*                     if (ScreenOfDisplay(_ecore_xcb_conn, i) == ps[j]) */
1157 /*                       overlap++; */
1158 /*                  } */
1159 /*             } */
1160 /*           roots = malloc((num - overlap) * sizeof(Ecore_X_Window)); */
1161 /*           if (roots) */
1162 /*             { */
1163 /*                int k; */
1164
1165 /*                k = 0; */
1166 /*                for (i = 0; i < num; i++) */
1167 /*                  { */
1168 /*                     int is_print; */
1169
1170 /*                     is_print = 0; */
1171 /*                     for (j = 0; j < psnum; j++) */
1172 /*                       { */
1173 /*                          if (ScreenOfDisplay(_ecore_xcb_conn, i) == ps[j]) */
1174 /*                            { */
1175 /*                               is_print = 1; */
1176 /*                               break; */
1177 /*                            } */
1178 /*                       } */
1179 /*                     if (!is_print) */
1180 /*                       { */
1181 /*                          roots[k] = RootWindow(_ecore_xcb_conn, i); */
1182 /*                          k++; */
1183 /*                       } */
1184 /*                  } */
1185 /*                *num_ret = k; */
1186 /*             } */
1187 /*           XFree(ps); */
1188 /*        } */
1189 /*      else */
1190 /*        { */
1191 /*           roots = malloc(num * sizeof(Ecore_X_Window)); */
1192 /*           if (!roots) return NULL; */
1193 /*           *num_ret = num; */
1194 /*           for (i = 0; i < num; i++) */
1195 /*             roots[i] = RootWindow(_ecore_xcb_conn, i); */
1196 /*        } */
1197 /*      } */
1198 /*    else */
1199 /*      { */
1200 /*      roots = malloc(num * sizeof(Ecore_X_Window)); */
1201 /*      if (!roots) return NULL; */
1202 /*      *num_ret = num; */
1203 /*      for (i = 0; i < num; i++) */
1204 /*        roots[i] = RootWindow(_ecore_xcb_conn, i); */
1205 /*      } */
1206 /* #else */
1207    setup = xcb_get_setup (_ecore_xcb_conn);
1208    iter = xcb_setup_roots_iterator (setup);
1209    num = setup->roots_len;
1210    roots = malloc(num * sizeof(Ecore_X_Window));
1211    if (!roots)
1212       return NULL;
1213
1214    *num_ret = num;
1215    for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
1216       roots[i] = iter.data->root;
1217 /* #endif /\* ECORE_XCBXPRINT *\/ */
1218
1219    return roots;
1220 } /* ecore_x_window_root_list */
1221
1222 EAPI Ecore_X_Window
1223 ecore_x_window_root_first_get(void)
1224 {
1225    Ecore_X_Window *roots = NULL;
1226    Ecore_X_Window root;
1227    int num;
1228
1229    roots = ecore_x_window_root_list(&num);
1230    if(!(roots))
1231       return 0;
1232
1233    if (num > 0)
1234       root = roots[0];
1235    else
1236       root = 0;
1237
1238    free(roots);
1239    return root;
1240 } /* ecore_x_window_root_first_get */
1241
1242 /* FIXME: todo */
1243
1244 static void      _ecore_x_window_manage_error(void *data);
1245
1246 static int _ecore_xcb_window_manage_failed = 0;
1247 static void
1248 _ecore_x_window_manage_error(void *data __UNUSED__)
1249 {
1250 /*    if ((ecore_xcb_error_request_get() == X_ChangeWindowAttributes) && */
1251 /*        (ecore_xcb_error_code_get() == BadAccess)) */
1252 /*      _ecore_xcb_window_manage_failed = 1; */
1253 } /* _ecore_x_window_manage_error */
1254
1255 /* FIXME: round trip */
1256 EAPI Eina_Bool
1257 ecore_x_window_manage(Ecore_X_Window window)
1258 {
1259    xcb_get_window_attributes_cookie_t cookie_attr;
1260    xcb_get_input_focus_cookie_t cookie_sync;
1261    xcb_get_window_attributes_reply_t *reply_attr;
1262    xcb_get_input_focus_reply_t *reply_sync;
1263    uint32_t value_list;
1264
1265    cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window);
1266    cookie_sync = xcb_get_input_focus_unchecked(_ecore_xcb_conn);
1267
1268    reply_attr = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_attr, NULL);
1269    if (!reply_attr)
1270      {
1271         reply_sync = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie_sync, NULL);
1272         if (reply_sync)
1273            free(reply_sync);
1274
1275         return 0;
1276      }
1277
1278    reply_sync = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie_sync, NULL);
1279    if (reply_sync)
1280       free(reply_sync);
1281
1282    _ecore_xcb_window_manage_failed = 0;
1283    /* FIXME: no error code yet */
1284    /* ecore_xcb_error_handler_set(_ecore_xcb_window_manage_error, NULL); */
1285
1286    value_list =
1287       XCB_EVENT_MASK_KEY_PRESS |
1288       XCB_EVENT_MASK_KEY_RELEASE |
1289       XCB_EVENT_MASK_ENTER_WINDOW |
1290       XCB_EVENT_MASK_LEAVE_WINDOW |
1291       XCB_EVENT_MASK_STRUCTURE_NOTIFY |
1292       XCB_EVENT_MASK_RESIZE_REDIRECT |
1293       XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
1294       XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
1295       XCB_EVENT_MASK_PROPERTY_CHANGE |
1296       reply_attr->your_event_mask;
1297    xcb_change_window_attributes(_ecore_xcb_conn, window,
1298                                 XCB_CW_EVENT_MASK,
1299                                 &value_list);
1300    free(reply_attr);
1301
1302    cookie_sync = xcb_get_input_focus_unchecked(_ecore_xcb_conn);
1303    if (reply_sync)
1304       free(reply_sync);
1305
1306    /* FIXME: no error code yet */
1307    /* ecore_xcb_error_handler_set(NULL, NULL); */
1308    if (_ecore_xcb_window_manage_failed)
1309      {
1310         _ecore_xcb_window_manage_failed = 0;
1311         return 0;
1312      }
1313
1314    return 1;
1315 } /* ecore_x_window_manage */
1316
1317 EAPI Eina_Bool
1318 ecore_x_pointer_control_set(int accel_num,
1319                             int accel_denom,
1320                             int threshold)
1321 {
1322    xcb_change_pointer_control(_ecore_xcb_conn,
1323                               accel_num, accel_denom, threshold,
1324                               1, 1);
1325    return 1;
1326 } /* ecore_x_pointer_control_set */
1327
1328 EAPI void
1329 ecore_x_pointer_control_get_prefetch(void)
1330 {
1331    xcb_get_pointer_control_cookie_t cookie;
1332
1333    cookie = xcb_get_pointer_control_unchecked(_ecore_xcb_conn);
1334    _ecore_xcb_cookie_cache(cookie.sequence);
1335 } /* ecore_x_pointer_control_get_prefetch */
1336
1337 EAPI void
1338 ecore_x_pointer_control_get_fetch(void)
1339 {
1340    xcb_get_pointer_control_cookie_t cookie;
1341    xcb_get_pointer_control_reply_t *reply;
1342
1343    cookie.sequence = _ecore_xcb_cookie_get();
1344    reply = xcb_get_pointer_control_reply(_ecore_xcb_conn, cookie, NULL);
1345    _ecore_xcb_reply_cache(reply);
1346 } /* ecore_x_pointer_control_get_fetch */
1347
1348 EAPI Eina_Bool
1349 ecore_x_pointer_control_get(int *accel_num,
1350                             int *accel_denom,
1351                             int *threshold)
1352 {
1353    xcb_get_pointer_control_reply_t *reply;
1354
1355    if (accel_num)
1356       *accel_num = 0;
1357
1358    if (accel_denom)
1359       *accel_denom = 1;
1360
1361    if (threshold)
1362       *threshold = 0;
1363
1364    reply = _ecore_xcb_reply_get();
1365    if (!reply)
1366       return 0;
1367
1368    if (accel_num)
1369       *accel_num = reply->acceleration_numerator;
1370
1371    if (accel_denom)
1372       *accel_denom = reply->acceleration_denominator;
1373
1374    if (threshold)
1375       *threshold = reply->threshold;
1376
1377    return 1;
1378 } /* ecore_x_pointer_control_get */
1379
1380 EAPI Eina_Bool
1381 ecore_x_pointer_mapping_set(unsigned char *map,
1382                             int            nmap)
1383 {
1384    xcb_set_pointer_mapping(_ecore_xcb_conn, nmap, map);
1385    return 1;
1386 } /* ecore_x_pointer_mapping_set */
1387
1388 EAPI void
1389 ecore_x_pointer_mapping_get_prefetch(void)
1390 {
1391    xcb_get_pointer_mapping_cookie_t cookie;
1392
1393    cookie = xcb_get_pointer_mapping_unchecked(_ecore_xcb_conn);
1394    _ecore_xcb_cookie_cache(cookie.sequence);
1395 } /* ecore_x_pointer_mapping_get_prefetch */
1396
1397 EAPI void
1398 ecore_x_pointer_mapping_get_fetch(void)
1399 {
1400    xcb_get_pointer_mapping_cookie_t cookie;
1401    xcb_get_pointer_mapping_reply_t *reply;
1402
1403    cookie.sequence = _ecore_xcb_cookie_get();
1404    reply = xcb_get_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
1405    _ecore_xcb_reply_cache(reply);
1406 } /* ecore_x_pointer_mapping_get_fetch */
1407
1408 EAPI Eina_Bool
1409 ecore_x_pointer_mapping_get(unsigned char *map,
1410                             int            nmap)
1411 {
1412    xcb_get_pointer_mapping_cookie_t cookie;
1413    xcb_get_pointer_mapping_reply_t *reply;
1414    uint8_t *tmp;
1415    int i;
1416
1417    cookie = xcb_get_pointer_mapping_unchecked(_ecore_xcb_conn);
1418    reply = xcb_get_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
1419    if (!reply)
1420       return 0;
1421
1422    if (nmap > xcb_get_pointer_mapping_map_length(reply))
1423       return 0;
1424
1425    tmp = xcb_get_pointer_mapping_map(reply);
1426
1427    for (i = 0; i < nmap; i++)
1428       map[i] = tmp[i];
1429
1430    return 1;
1431 } /* ecore_x_pointer_mapping_get */
1432
1433 EAPI Eina_Bool
1434 ecore_x_pointer_grab(Ecore_X_Window window)
1435 {
1436    xcb_grab_pointer_cookie_t cookie;
1437    xcb_grab_pointer_reply_t *reply;
1438
1439    cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, window,
1440                                        XCB_EVENT_MASK_BUTTON_PRESS |
1441                                        XCB_EVENT_MASK_BUTTON_RELEASE |
1442                                        XCB_EVENT_MASK_ENTER_WINDOW |
1443                                        XCB_EVENT_MASK_LEAVE_WINDOW |
1444                                        XCB_EVENT_MASK_POINTER_MOTION,
1445                                        XCB_GRAB_MODE_ASYNC,
1446                                        XCB_GRAB_MODE_ASYNC,
1447                                        XCB_NONE, XCB_NONE,
1448                                        XCB_CURRENT_TIME);
1449    reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
1450    if (!reply)
1451       return 0;
1452
1453    free(reply);
1454
1455    return 1;
1456 } /* ecore_x_pointer_grab */
1457
1458 EAPI Eina_Bool
1459 ecore_x_pointer_confine_grab(Ecore_X_Window window)
1460 {
1461    xcb_grab_pointer_cookie_t cookie;
1462    xcb_grab_pointer_reply_t *reply;
1463
1464    cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, window,
1465                                        XCB_EVENT_MASK_BUTTON_PRESS |
1466                                        XCB_EVENT_MASK_BUTTON_RELEASE |
1467                                        XCB_EVENT_MASK_ENTER_WINDOW |
1468                                        XCB_EVENT_MASK_LEAVE_WINDOW |
1469                                        XCB_EVENT_MASK_POINTER_MOTION,
1470                                        XCB_GRAB_MODE_ASYNC,
1471                                        XCB_GRAB_MODE_ASYNC,
1472                                        window, XCB_NONE,
1473                                        XCB_CURRENT_TIME);
1474    reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
1475    if (!reply)
1476       return 0;
1477
1478    free(reply);
1479
1480    return 1;
1481 } /* ecore_x_pointer_confine_grab */
1482
1483 EAPI void
1484 ecore_x_pointer_ungrab(void)
1485 {
1486    xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME);
1487 } /* ecore_x_pointer_ungrab */
1488
1489 EAPI Eina_Bool
1490 ecore_x_pointer_warp(Ecore_X_Window window,
1491                      int            x,
1492                      int            y)
1493 {
1494    xcb_warp_pointer(_ecore_xcb_conn, XCB_NONE, window, 0, 0, 0, 0, x, y);
1495
1496    return 1;
1497 } /* ecore_x_pointer_warp */
1498
1499 EAPI Eina_Bool
1500 ecore_x_keyboard_grab(Ecore_X_Window window)
1501 {
1502    xcb_grab_keyboard_cookie_t cookie;
1503    xcb_grab_keyboard_reply_t *reply;
1504
1505    cookie = xcb_grab_keyboard_unchecked(_ecore_xcb_conn, 0, window,
1506                                         XCB_CURRENT_TIME,
1507                                         XCB_GRAB_MODE_ASYNC,
1508                                         XCB_GRAB_MODE_ASYNC);
1509    reply = xcb_grab_keyboard_reply(_ecore_xcb_conn, cookie, NULL);
1510    if (!reply)
1511       return 0;
1512
1513    free(reply);
1514
1515    return 1;
1516 } /* ecore_x_keyboard_grab */
1517
1518 EAPI void
1519 ecore_x_keyboard_ungrab(void)
1520 {
1521    xcb_ungrab_keyboard(_ecore_xcb_conn, XCB_CURRENT_TIME);
1522 } /* ecore_x_keyboard_ungrab */
1523
1524 EAPI void
1525 ecore_x_grab(void)
1526 {
1527    _ecore_xcb_grab_count++;
1528
1529    if (_ecore_xcb_grab_count == 1)
1530       xcb_grab_server(_ecore_xcb_conn);
1531 } /* ecore_x_grab */
1532
1533 EAPI void
1534 ecore_x_ungrab(void)
1535 {
1536    _ecore_xcb_grab_count--;
1537    if (_ecore_xcb_grab_count < 0)
1538       _ecore_xcb_grab_count = 0;
1539
1540    if (_ecore_xcb_grab_count == 0)
1541      {
1542         xcb_ungrab_server(_ecore_xcb_conn);
1543         free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), NULL));
1544      }
1545 } /* ecore_x_ungrab */
1546
1547 int _ecore_window_grabs_num = 0;
1548 Ecore_X_Window *_ecore_window_grabs = NULL;
1549 Eina_Bool (*_ecore_window_grab_replay_func)(void *data, int event_type, void *event);
1550 void *_ecore_window_grab_replay_data;
1551
1552 EAPI void
1553 ecore_x_passive_grab_replay_func_set(Eina_Bool                             (*func)(void *data,
1554                                                                      int   event_type,
1555                                                                      void *event),
1556                                      void                                 *data)
1557 {
1558    _ecore_window_grab_replay_func = func;
1559    _ecore_window_grab_replay_data = data;
1560 } /* ecore_x_passive_grab_replay_func_set */
1561
1562 EAPI void
1563 ecore_x_window_button_grab(Ecore_X_Window     window,
1564                            int                button,
1565                            Ecore_X_Event_Mask event_mask,
1566                            int                mod,
1567                            int                any_mod)
1568 {
1569    int i;
1570    uint16_t m;
1571    uint16_t locks[8];
1572    uint16_t ev;
1573
1574    m = _ecore_xcb_event_modifier(mod);
1575    if (any_mod)
1576       m = XCB_BUTTON_MASK_ANY;
1577
1578    locks[0] = 0;
1579    locks[1] = ECORE_X_LOCK_CAPS;
1580    locks[2] = ECORE_X_LOCK_NUM;
1581    locks[3] = ECORE_X_LOCK_SCROLL;
1582    locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
1583    locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
1584    locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1585    locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1586    ev = event_mask;
1587    for (i = 0; i < 8; i++)
1588       xcb_grab_button(_ecore_xcb_conn, 0, window, ev,
1589                       XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
1590                       XCB_NONE, XCB_NONE, button, m | locks[i]);
1591    _ecore_window_grabs_num++;
1592    _ecore_window_grabs = realloc(_ecore_window_grabs,
1593                                  _ecore_window_grabs_num * sizeof(Ecore_X_Window));
1594    _ecore_window_grabs[_ecore_window_grabs_num - 1] = window;
1595 } /* ecore_x_window_button_grab */
1596
1597 void
1598 _ecore_x_sync_magic_send(int            val,
1599                          Ecore_X_Window swindow)
1600 {
1601    xcb_client_message_event_t ev;
1602
1603    ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
1604    ev.format = 32;
1605    ev.window = _ecore_xcb_private_window;
1606    ev.type = 27777;
1607    ev.data.data32[0] = 0x7162534;
1608    ev.data.data32[1] = 0x10000000 + val;
1609    ev.data.data32[2] = swindow;
1610
1611    xcb_send_event(_ecore_xcb_conn, 0, _ecore_xcb_private_window,
1612                   XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
1613 } /* _ecore_x_sync_magic_send */
1614
1615 void
1616 _ecore_x_window_grab_remove(Ecore_X_Window window)
1617 {
1618    int i, shuffle = 0;
1619
1620    if (_ecore_window_grabs_num > 0)
1621      {
1622         for (i = 0; i < _ecore_window_grabs_num; i++)
1623           {
1624              if (shuffle)
1625                 _ecore_window_grabs[i - 1] = _ecore_window_grabs[i];
1626
1627              if ((!shuffle) && (_ecore_window_grabs[i] == window))
1628                 shuffle = 1;
1629           }
1630         if (shuffle)
1631           {
1632              _ecore_window_grabs_num--;
1633              _ecore_window_grabs = realloc(_ecore_window_grabs,
1634                                            _ecore_window_grabs_num * sizeof(Ecore_X_Window));
1635           }
1636      }
1637 } /* _ecore_x_window_grab_remove */
1638
1639 EAPI void
1640 ecore_x_window_button_ungrab(Ecore_X_Window window,
1641                              int            button,
1642                              int            mod,
1643                              int            any_mod)
1644 {
1645    int i;
1646    uint16_t m;
1647    uint16_t locks[8];
1648
1649    m = _ecore_xcb_event_modifier(mod);
1650    if (any_mod)
1651       m = XCB_BUTTON_MASK_ANY;
1652
1653    locks[0] = 0;
1654    locks[1] = ECORE_X_LOCK_CAPS;
1655    locks[2] = ECORE_X_LOCK_NUM;
1656    locks[3] = ECORE_X_LOCK_SCROLL;
1657    locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
1658    locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
1659    locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1660    locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1661    for (i = 0; i < 8; i++)
1662       xcb_ungrab_button(_ecore_xcb_conn, button, window, m | locks[i]);
1663    _ecore_x_sync_magic_send(1, window);
1664 } /* ecore_x_window_button_ungrab */
1665
1666 int _ecore_key_grabs_num = 0;
1667 Ecore_X_Window *_ecore_key_grabs = NULL;
1668
1669 EAPI void
1670 ecore_x_window_key_grab(Ecore_X_Window window,
1671                         const char    *key,
1672                         int            mod,
1673                         int            any_mod)
1674 {
1675    xcb_keycode_t keycode = 0;
1676    uint16_t m;
1677    uint16_t locks[8];
1678    int i;
1679
1680    if (!strncmp(key, "Keycode-", 8))
1681       keycode = atoi(key + 8);
1682
1683    /* FIXME: TODO... */
1684
1685 /*    else */
1686 /*      { */
1687 /*         KeySym              keysym; */
1688
1689 /*      keysym = XStringToKeysym(key); */
1690 /*      if (keysym == NoSymbol) return; */
1691 /*      keycode  = XKeysymToKeycode(_ecore_xcb_conn, XStringToKeysym(key)); */
1692 /*      } */
1693    if (keycode == 0)
1694       return;
1695
1696    m = _ecore_xcb_event_modifier(mod);
1697    if (any_mod)
1698       m = XCB_BUTTON_MASK_ANY;
1699
1700    locks[0] = 0;
1701    locks[1] = ECORE_X_LOCK_CAPS;
1702    locks[2] = ECORE_X_LOCK_NUM;
1703    locks[3] = ECORE_X_LOCK_SCROLL;
1704    locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
1705    locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
1706    locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1707    locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1708    for (i = 0; i < 8; i++)
1709       xcb_grab_key(_ecore_xcb_conn, 1, window, m | locks[i], keycode,
1710                    XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
1711    _ecore_key_grabs_num++;
1712    _ecore_key_grabs = realloc(_ecore_key_grabs,
1713                               _ecore_key_grabs_num * sizeof(Ecore_X_Window));
1714    _ecore_key_grabs[_ecore_key_grabs_num - 1] = window;
1715 } /* ecore_x_window_key_grab */
1716
1717 void
1718 _ecore_x_key_grab_remove(Ecore_X_Window window)
1719 {
1720    int i, shuffle = 0;
1721
1722    if (_ecore_key_grabs_num > 0)
1723      {
1724         for (i = 0; i < _ecore_key_grabs_num; i++)
1725           {
1726              if (shuffle)
1727                 _ecore_key_grabs[i - 1] = _ecore_key_grabs[i];
1728
1729              if ((!shuffle) && (_ecore_key_grabs[i] == window))
1730                 shuffle = 1;
1731           }
1732         if (shuffle)
1733           {
1734              _ecore_key_grabs_num--;
1735              _ecore_key_grabs = realloc(_ecore_key_grabs,
1736                                         _ecore_key_grabs_num * sizeof(Ecore_X_Window));
1737           }
1738      }
1739 } /* _ecore_x_key_grab_remove */
1740
1741 EAPI void
1742 ecore_x_window_key_ungrab(Ecore_X_Window window,
1743                           const char    *key,
1744                           int            mod,
1745                           int            any_mod)
1746 {
1747    xcb_keycode_t keycode = 0;
1748    uint16_t m;
1749    uint16_t locks[8];
1750    int i;
1751
1752    if (!strncmp(key, "Keycode-", 8))
1753       keycode = atoi(key + 8);
1754
1755    /* FIXME: todo... */
1756
1757 /*    else */
1758 /*      { */
1759 /*         KeySym              keysym; */
1760
1761 /*      keysym = XStringToKeysym(key); */
1762 /*      if (keysym == NoSymbol) return; */
1763 /*      keycode  = XKeysymToKeycode(_ecore_xcb_conn, XStringToKeysym(key)); */
1764 /*      } */
1765    if (keycode == 0)
1766       return;
1767
1768    m = _ecore_xcb_event_modifier(mod);
1769    if (any_mod)
1770       m = XCB_BUTTON_MASK_ANY;
1771
1772    locks[0] = 0;
1773    locks[1] = ECORE_X_LOCK_CAPS;
1774    locks[2] = ECORE_X_LOCK_NUM;
1775    locks[3] = ECORE_X_LOCK_SCROLL;
1776    locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
1777    locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
1778    locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1779    locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
1780    for (i = 0; i < 8; i++)
1781       xcb_ungrab_key(_ecore_xcb_conn, keycode, window, m | locks[i]);
1782    _ecore_x_sync_magic_send(2, window);
1783 } /* ecore_x_window_key_ungrab */
1784
1785 /**
1786  * Send client message with given type and format 32.
1787  *
1788  * @param window  The window the message is sent to.
1789  * @param type    The client message type.
1790  * @param mask    The client message mask.
1791  * @param d0      The client message data item 1
1792  * @param d1      The client message data item 2
1793  * @param d2      The client message data item 3
1794  * @param d3      The client message data item 4
1795  * @param d4      The client message data item 5
1796  *
1797  * @return !0 on success.
1798  */
1799 EAPI Eina_Bool
1800 ecore_x_client_message32_send(Ecore_X_Window     window,
1801                               Ecore_X_Atom       type,
1802                               Ecore_X_Event_Mask mask,
1803                               long               d0,
1804                               long               d1,
1805                               long               d2,
1806                               long               d3,
1807                               long               d4)
1808 {
1809    xcb_client_message_event_t ev;
1810
1811    ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
1812    ev.format = 32;
1813    ev.window = window;
1814    ev.type = type;
1815    ev.data.data32[0] = d0;
1816    ev.data.data32[1] = d1;
1817    ev.data.data32[2] = d2;
1818    ev.data.data32[3] = d3;
1819    ev.data.data32[4] = d4;
1820
1821    xcb_send_event(_ecore_xcb_conn, 0, window, mask, (const char *)&ev);
1822
1823    return 1;
1824 } /* ecore_x_client_message32_send */
1825
1826 /**
1827  * Send client message with given type and format 8.
1828  *
1829  * @param window  The window the message is sent to.
1830  * @param type    The client message type.
1831  * @param data    Data to be sent.
1832  * @param len     Number of data bytes, max 20.
1833  *
1834  * @return !0 on success.
1835  */
1836 EAPI Eina_Bool
1837 ecore_x_client_message8_send(Ecore_X_Window window,
1838                              Ecore_X_Atom   type,
1839                              const void    *data,
1840                              int            len)
1841 {
1842    xcb_client_message_event_t ev;
1843
1844    ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
1845    ev.format = 8;
1846    ev.window = window;
1847    ev.type = type;
1848    if (len > 20)
1849       len = 20;
1850
1851    memcpy(ev.data.data8, data, len);
1852    memset(ev.data.data8 + len, 0, 20 - len);
1853
1854    xcb_send_event(_ecore_xcb_conn, 0, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
1855
1856    return 1;
1857 } /* ecore_x_client_message8_send */
1858
1859 /* FIXME: round trip */
1860 EAPI Eina_Bool
1861 ecore_x_mouse_move_send(Ecore_X_Window window,
1862                         int            x,
1863                         int            y)
1864 {
1865    xcb_motion_notify_event_t ev;
1866    xcb_get_geometry_cookie_t cookie_geom;
1867    xcb_translate_coordinates_cookie_t cookie_trans;
1868    xcb_get_geometry_reply_t *reply_geom;
1869    xcb_translate_coordinates_reply_t *reply_trans;
1870
1871    cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window);
1872    reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL);
1873    if (!reply_geom)
1874       return 0;
1875
1876    cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y);
1877    reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL);
1878    if (!reply_trans)
1879      {
1880         free(reply_geom);
1881         return 0;
1882      }
1883
1884    ev.response_type = XCB_MOTION_NOTIFY;
1885    ev.detail = 0;
1886    ev.time = _ecore_xcb_event_last_time;
1887    ev.root = reply_geom->root;
1888    ev.event = window;
1889    ev.child = window;
1890    ev.root_x = reply_trans->dst_x;
1891    ev.root_y = reply_trans->dst_y;
1892    ev.event_x = x;
1893    ev.event_y = y;
1894    ev.state = 0;
1895    ev.same_screen = 1;
1896
1897    xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_POINTER_MOTION, (const char *)&ev);
1898
1899    free(reply_geom);
1900    free(reply_trans);
1901
1902    return 1;
1903 } /* ecore_x_mouse_move_send */
1904
1905 /* FIXME: round trip */
1906 EAPI Eina_Bool
1907 ecore_x_mouse_down_send(Ecore_X_Window window,
1908                         int            x,
1909                         int            y,
1910                         int            button)
1911 {
1912    xcb_button_press_event_t ev;
1913    xcb_get_geometry_cookie_t cookie_geom;
1914    xcb_translate_coordinates_cookie_t cookie_trans;
1915    xcb_get_geometry_reply_t *reply_geom;
1916    xcb_translate_coordinates_reply_t *reply_trans;
1917
1918    cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window);
1919    reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL);
1920    if (!reply_geom)
1921       return 0;
1922
1923    cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y);
1924    reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL);
1925    if (!reply_trans)
1926      {
1927         free(reply_geom);
1928         return 0;
1929      }
1930
1931    ev.response_type = XCB_BUTTON_PRESS;
1932    ev.detail = button;
1933    ev.time = _ecore_xcb_event_last_time;
1934    ev.root = reply_geom->root;
1935    ev.event = window;
1936    ev.child = window;
1937    ev.root_x = reply_trans->dst_x;
1938    ev.root_y = reply_trans->dst_y;
1939    ev.event_x = x;
1940    ev.event_y = y;
1941    ev.state = 1 << button;
1942    ev.same_screen = 1;
1943
1944    xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_BUTTON_PRESS, (const char *)&ev);
1945
1946    free(reply_geom);
1947    free(reply_trans);
1948
1949    return 1;
1950 } /* ecore_x_mouse_down_send */
1951
1952 /* FIXME: round trip */
1953 EAPI Eina_Bool
1954 ecore_x_mouse_up_send(Ecore_X_Window window,
1955                       int            x,
1956                       int            y,
1957                       int            button)
1958 {
1959    xcb_button_release_event_t ev;
1960    xcb_get_geometry_cookie_t cookie_geom;
1961    xcb_translate_coordinates_cookie_t cookie_trans;
1962    xcb_get_geometry_reply_t *reply_geom;
1963    xcb_translate_coordinates_reply_t *reply_trans;
1964
1965    cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window);
1966    reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL);
1967    if (!reply_geom)
1968       return 0;
1969
1970    cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y);
1971    reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL);
1972    if (!reply_trans)
1973      {
1974         free(reply_geom);
1975         return 0;
1976      }
1977
1978    ev.response_type = XCB_BUTTON_RELEASE;
1979    ev.detail = button;
1980    ev.time = _ecore_xcb_event_last_time;
1981    ev.root = reply_geom->root;
1982    ev.event = window;
1983    ev.child = window;
1984    ev.root_x = reply_trans->dst_x;
1985    ev.root_y = reply_trans->dst_y;
1986    ev.event_x = x;
1987    ev.event_y = y;
1988    ev.state = 0;
1989    ev.same_screen = 1;
1990
1991    xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev);
1992
1993    free(reply_geom);
1994    free(reply_trans);
1995
1996    return 1;
1997 } /* ecore_x_mouse_up_send */
1998
1999 EAPI void
2000 ecore_x_focus_reset(void)
2001 {
2002    xcb_set_input_focus(_ecore_xcb_conn,
2003                        (uint8_t)XCB_INPUT_FOCUS_POINTER_ROOT,
2004                        XCB_INPUT_FOCUS_POINTER_ROOT,
2005                        XCB_CURRENT_TIME);
2006 } /* ecore_x_focus_reset */
2007
2008 EAPI void
2009 ecore_x_events_allow_all(void)
2010 {
2011    xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME);
2012 } /* ecore_x_events_allow_all */
2013
2014 EAPI void
2015 ecore_x_pointer_last_xy_get(int *x,
2016                             int *y)
2017 {
2018    if (x)
2019       *x = _ecore_xcb_event_last_root_x;
2020
2021    if (y)
2022       *y = _ecore_xcb_event_last_root_y;
2023 } /* ecore_x_pointer_last_xy_get */
2024
2025 /*****************************************************************************/
2026 /*****************************************************************************/
2027 /*****************************************************************************/
2028
2029 static int
2030 _ecore_xcb_event_modifier(unsigned int state)
2031 {
2032    int xmodifiers = 0;
2033
2034    if (state & ECORE_EVENT_MODIFIER_SHIFT)
2035       xmodifiers |= ECORE_X_MODIFIER_SHIFT;
2036
2037    if (state & ECORE_EVENT_MODIFIER_CTRL)
2038       xmodifiers |= ECORE_X_MODIFIER_CTRL;
2039
2040    if (state & ECORE_EVENT_MODIFIER_ALT)
2041       xmodifiers |= ECORE_X_MODIFIER_ALT;
2042
2043    if (state & ECORE_EVENT_MODIFIER_WIN)
2044       xmodifiers |= ECORE_X_MODIFIER_WIN;
2045
2046    if (state & ECORE_EVENT_LOCK_SCROLL)
2047       xmodifiers |= ECORE_X_LOCK_SCROLL;
2048
2049    if (state & ECORE_EVENT_LOCK_NUM)
2050       xmodifiers |= ECORE_X_LOCK_NUM;
2051
2052    if (state & ECORE_EVENT_LOCK_CAPS)
2053       xmodifiers |= ECORE_X_LOCK_CAPS;
2054
2055    return xmodifiers;
2056 } /* _ecore_xcb_event_modifier */
2057