2 * Copyright © 2013 Ran Benita
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
27 xkb_x11_setup_xkb_extension(xcb_connection_t *conn,
28 uint16_t major_xkb_version,
29 uint16_t minor_xkb_version,
30 enum xkb_x11_setup_xkb_extension_flags flags,
31 uint16_t *major_xkb_version_out,
32 uint16_t *minor_xkb_version_out,
33 uint8_t *base_event_out,
34 uint8_t *base_error_out)
36 uint8_t base_event, base_error;
37 uint16_t server_major, server_minor;
39 if (flags & ~(XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS)) {
40 /* log_err_func(ctx, "unrecognized flags: %#x\n", flags); */
45 const xcb_query_extension_reply_t *reply =
46 xcb_get_extension_data(conn, &xcb_xkb_id);
48 /* log_err_func(ctx, "failed to query for XKB extension\n"); */
52 if (!reply->present) {
53 /* log_err_func(ctx, "failed to start using XKB extension: not available in server\n"); */
57 base_event = reply->first_event;
58 base_error = reply->first_error;
62 xcb_generic_error_t *error = NULL;
63 xcb_xkb_use_extension_cookie_t cookie =
64 xcb_xkb_use_extension(conn, major_xkb_version, minor_xkb_version);
65 xcb_xkb_use_extension_reply_t *reply =
66 xcb_xkb_use_extension_reply(conn, cookie, &error);
69 /* log_err_func(ctx, */
70 /* "failed to start using XKB extension: error code %d\n", */
71 /* error ? error->error_code : -1); */
76 if (!reply->supported) {
77 /* log_err_func(ctx, */
78 /* "failed to start using XKB extension: server doesn't support version %d.%d\n", */
79 /* major_xkb_version, minor_xkb_version); */
84 server_major = reply->serverMajor;
85 server_minor = reply->serverMinor;
91 * The XkbUseExtension() in libX11 has a *bunch* of legacy stuff, but
92 * it doesn't seem like any of it is useful to us.
95 if (major_xkb_version_out)
96 *major_xkb_version_out = server_major;
97 if (minor_xkb_version_out)
98 *minor_xkb_version_out = server_minor;
100 *base_event_out = base_event;
102 *base_error_out = base_error;
108 xkb_x11_get_core_keyboard_device_id(xcb_connection_t *conn)
111 xcb_xkb_get_device_info_cookie_t cookie =
112 xcb_xkb_get_device_info(conn, XCB_XKB_ID_USE_CORE_KBD,
114 xcb_xkb_get_device_info_reply_t *reply =
115 xcb_xkb_get_device_info_reply(conn, cookie, NULL);
120 device_id = reply->deviceID;
126 get_atom_name(xcb_connection_t *conn, xcb_atom_t atom, char **out)
128 xcb_get_atom_name_cookie_t cookie;
129 xcb_get_atom_name_reply_t *reply;
138 cookie = xcb_get_atom_name(conn, atom);
139 reply = xcb_get_atom_name_reply(conn, cookie, NULL);
143 length = xcb_get_atom_name_name_length(reply);
144 name = xcb_get_atom_name_name(reply);
146 *out = strndup(name, length);
157 adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
158 const xcb_atom_t *from, xkb_atom_t *to, const size_t count)
161 xcb_get_atom_name_cookie_t cookies[SIZE];
163 /* Send and collect the atoms in batches of reasonable SIZE. */
164 for (size_t batch = 0; batch <= count / SIZE; batch++) {
165 const size_t start = batch * SIZE;
166 const size_t stop = min((batch + 1) * SIZE, count);
169 for (size_t i = start; i < stop; i++)
170 if (from[i] != XCB_ATOM_NONE)
171 cookies[i % SIZE] = xcb_get_atom_name(conn, from[i]);
174 for (size_t i = start; i < stop; i++) {
175 xcb_get_atom_name_reply_t *reply;
177 if (from[i] == XCB_ATOM_NONE) {
178 to[i] = XKB_ATOM_NONE;
182 reply = xcb_get_atom_name_reply(conn, cookies[i % SIZE], NULL);
186 to[i] = xkb_atom_intern(ctx,
187 xcb_get_atom_name_name(reply),
188 xcb_get_atom_name_name_length(reply));
191 if (to[i] == XKB_ATOM_NONE)
197 * If we don't discard the uncollected replies, they just
198 * sit there waiting. Sad.
201 for (size_t j = i + 1; j < stop; j++)
202 xcb_discard_reply(conn, cookies[j].sequence);
211 adopt_atom(struct xkb_context *ctx, xcb_connection_t *conn, xcb_atom_t atom,
214 return adopt_atoms(ctx, conn, &atom, out, 1);