1 /* 2 * Copyright 2013 Ran Benita 3 * 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: 10 * 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 13 * Software. 14 * 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. 22 */ 23 24 #include "x11-priv.h" 25 26 XKB_EXPORT int 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) 35 { 36 uint8_t base_event, base_error; 37 uint16_t server_major, server_minor; 38 39 if (flags & ~(XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS)) { 40 /* log_err_func(ctx, "unrecognized flags: %#x\n", flags); */ 41 return 0; 42 } 43 44 { 45 const xcb_query_extension_reply_t *reply = 46 xcb_get_extension_data(conn, &xcb_xkb_id); 47 if (!reply) { 48 /* log_err_func(ctx, "failed to query for XKB extension\n"); */ 49 return 0; 50 } 51 52 if (!reply->present) { 53 /* log_err_func(ctx, "failed to start using XKB extension: not available in server\n"); */ 54 return 0; 55 } 56 57 base_event = reply->first_event; 58 base_error = reply->first_error; 59 } 60 61 { 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); 67 68 if (!reply) { 69 /* log_err_func(ctx, */ 70 /* "failed to start using XKB extension: error code %d\n", */ 71 /* error ? error->error_code : -1); */ 72 free(error); 73 return 0; 74 } 75 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); */ 80 free(reply); 81 return 0; 82 } 83 84 server_major = reply->serverMajor; 85 server_minor = reply->serverMinor; 86 87 free(reply); 88 } 89 90 /* 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. 93 */ 94 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; 99 if (base_event_out) 100 *base_event_out = base_event; 101 if (base_error_out) 102 *base_error_out = base_error; 103 104 return 1; 105 } 106 107 XKB_EXPORT int32_t 108 xkb_x11_get_core_keyboard_device_id(xcb_connection_t *conn) 109 { 110 int32_t device_id; 111 xcb_xkb_get_device_info_cookie_t cookie = 112 xcb_xkb_get_device_info(conn, XCB_XKB_ID_USE_CORE_KBD, 113 0, 0, 0, 0, 0, 0); 114 xcb_xkb_get_device_info_reply_t *reply = 115 xcb_xkb_get_device_info_reply(conn, cookie, NULL); 116 117 if (!reply) 118 return -1; 119 120 device_id = reply->deviceID; 121 free(reply); 122 return device_id; 123 } 124 125 bool 126 get_atom_name(xcb_connection_t *conn, xcb_atom_t atom, char **out) 127 { 128 xcb_get_atom_name_cookie_t cookie; 129 xcb_get_atom_name_reply_t *reply; 130 int length; 131 char *name; 132 133 if (atom == 0) { 134 *out = NULL; 135 return true; 136 } 137 138 cookie = xcb_get_atom_name(conn, atom); 139 reply = xcb_get_atom_name_reply(conn, cookie, NULL); 140 if (!reply) 141 return false; 142 143 length = xcb_get_atom_name_name_length(reply); 144 name = xcb_get_atom_name_name(reply); 145 146 *out = strndup(name, length); 147 if (!*out) { 148 free(reply); 149 return false; 150 } 151 152 free(reply); 153 return true; 154 } 155 156 bool 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) 159 { 160 enum { SIZE = 128 }; 161 xcb_get_atom_name_cookie_t cookies[SIZE]; 162 const size_t num_batches = ROUNDUP(count, SIZE) / SIZE; 163 164 /* Send and collect the atoms in batches of reasonable SIZE. */ 165 for (size_t batch = 0; batch < num_batches; batch++) { 166 const size_t start = batch * SIZE; 167 const size_t stop = min((batch + 1) * SIZE, count); 168 169 /* Send. */ 170 for (size_t i = start; i < stop; i++) 171 if (from[i] != XCB_ATOM_NONE) 172 cookies[i % SIZE] = xcb_get_atom_name(conn, from[i]); 173 174 /* Collect. */ 175 for (size_t i = start; i < stop; i++) { 176 xcb_get_atom_name_reply_t *reply; 177 178 if (from[i] == XCB_ATOM_NONE) { 179 to[i] = XKB_ATOM_NONE; 180 continue; 181 } 182 183 reply = xcb_get_atom_name_reply(conn, cookies[i % SIZE], NULL); 184 if (!reply) 185 goto err_discard; 186 187 to[i] = xkb_atom_intern(ctx, 188 xcb_get_atom_name_name(reply), 189 xcb_get_atom_name_name_length(reply)); 190 free(reply); 191 192 if (to[i] == XKB_ATOM_NONE) 193 goto err_discard; 194 195 continue; 196 197 /* 198 * If we don't discard the uncollected replies, they just 199 * sit in the XCB queue waiting forever. Sad. 200 */ 201 err_discard: 202 for (size_t j = i + 1; j < stop; j++) 203 if (from[j] != XCB_ATOM_NONE) 204 xcb_discard_reply(conn, cookies[j % SIZE].sequence); 205 return false; 206 } 207 } 208 209 return true; 210 } 211 212 bool 213 adopt_atom(struct xkb_context *ctx, xcb_connection_t *conn, xcb_atom_t atom, 214 xkb_atom_t *out) 215 { 216 return adopt_atoms(ctx, conn, &atom, out, 1); 217 } 218