Messages: merge macros with and without message code
[platform/upstream/libxkbcommon.git] / src / x11 / keymap.c
index aa91033..72f6639 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include "config.h"
+
 #include "x11-priv.h"
 
 /*
  * References for the lonesome traveler:
  * Xkb protocol specification:
- *      http://www.x.org/releases/current/doc/kbproto/xkbproto.html
+ *      https://www.x.org/releases/current/doc/kbproto/xkbproto.html
  * The XCB xkb XML protocol file:
  *      /user/share/xcb/xkb.xml
  * The XCB xkb header file:
  * We try not to trust the server too much and be paranoid. If we get
  * something which we definitely shouldn't, we fail.
  */
-#define STRINGIFY(expr) #expr
 #define FAIL_UNLESS(expr) do {                                          \
     if (!(expr)) {                                                      \
-        log_err(keymap->ctx,                                            \
+        log_err(keymap->ctx, XKB_LOG_MESSAGE_NO_ID,                                            \
                 "x11: failed to get keymap from X server: unmet condition in %s(): %s\n", \
                 __func__, STRINGIFY(expr));                             \
         goto fail;                                                      \
@@ -71,7 +72,7 @@
 
 #define FAIL_IF_BAD_REPLY(reply, request_name) do {                     \
     if (!reply) {                                                       \
-        log_err(keymap->ctx,                                            \
+        log_err(keymap->ctx, XKB_LOG_MESSAGE_NO_ID,                                            \
                 "x11: failed to get keymap from X server: %s request failed\n", \
                 (request_name));                                        \
         goto fail;                                                      \
     }                                                                   \
 } while (0)
 
+static const xcb_xkb_map_part_t get_map_required_components =
+    (XCB_XKB_MAP_PART_KEY_TYPES |
+     XCB_XKB_MAP_PART_KEY_SYMS |
+     XCB_XKB_MAP_PART_MODIFIER_MAP |
+     XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+     XCB_XKB_MAP_PART_KEY_ACTIONS |
+     XCB_XKB_MAP_PART_VIRTUAL_MODS |
+     XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
+
+static const xcb_xkb_name_detail_t get_names_wanted =
+    (XCB_XKB_NAME_DETAIL_KEYCODES |
+     XCB_XKB_NAME_DETAIL_SYMBOLS |
+     XCB_XKB_NAME_DETAIL_TYPES |
+     XCB_XKB_NAME_DETAIL_COMPAT |
+     XCB_XKB_NAME_DETAIL_KEY_TYPE_NAMES |
+     XCB_XKB_NAME_DETAIL_KT_LEVEL_NAMES |
+     XCB_XKB_NAME_DETAIL_INDICATOR_NAMES |
+     XCB_XKB_NAME_DETAIL_KEY_NAMES |
+     XCB_XKB_NAME_DETAIL_KEY_ALIASES |
+     XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES |
+     XCB_XKB_NAME_DETAIL_GROUP_NAMES);
+static const xcb_xkb_name_detail_t get_names_required =
+    (XCB_XKB_NAME_DETAIL_KEY_TYPE_NAMES |
+     XCB_XKB_NAME_DETAIL_KT_LEVEL_NAMES |
+     XCB_XKB_NAME_DETAIL_KEY_NAMES |
+     XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES);
+
 
 static xkb_mod_mask_t
 translate_mods(uint8_t rmods, uint16_t vmods_low, uint16_t vmods_high)
@@ -218,11 +246,11 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire)
     case XCB_XKB_SA_TYPE_MOVE_PTR:
         action->type = ACTION_TYPE_PTR_MOVE;
 
-        action->ptr.x = (wire->moveptr.xLow | (wire->moveptr.xHigh << 8));
-        action->ptr.y = (wire->moveptr.yLow | (wire->moveptr.yHigh << 8));
+        action->ptr.x = (int16_t) (wire->moveptr.xLow | ((uint16_t) wire->moveptr.xHigh << 8));
+        action->ptr.y = (int16_t) (wire->moveptr.yLow | ((uint16_t) wire->moveptr.yHigh << 8));
 
-        if (wire->moveptr.flags & XCB_XKB_SA_MOVE_PTR_FLAG_NO_ACCELERATION)
-            action->ptr.flags |= ACTION_NO_ACCEL;
+        if (!(wire->moveptr.flags & XCB_XKB_SA_MOVE_PTR_FLAG_NO_ACCELERATION))
+            action->ptr.flags |= ACTION_ACCEL;
         if (wire->moveptr.flags & XCB_XKB_SA_MOVE_PTR_FLAG_MOVE_ABSOLUTE_X)
             action->ptr.flags |= ACTION_ABSOLUTE_X;
         if (wire->moveptr.flags & XCB_XKB_SA_MOVE_PTR_FLAG_MOVE_ABSOLUTE_Y)
@@ -266,7 +294,7 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire)
 
         action->screen.screen = wire->switchscreen.newScreen;
 
-        if (wire->switchscreen.flags & XCB_XKB_SWITCH_SCREEN_FLAG_APPLICATION)
+        if (!(wire->switchscreen.flags & XCB_XKB_SWITCH_SCREEN_FLAG_APPLICATION))
             action->screen.flags |= ACTION_SAME_SCREEN;
         if (wire->switchscreen.flags & XCB_XKB_SWITCH_SCREEN_FLAG_ABSOLUTE)
             action->screen.flags |= ACTION_ABSOLUTE_SWITCH;
@@ -299,6 +327,20 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire)
     case XCB_XKB_SA_TYPE_DEVICE_VALUATOR:
         action->type = ACTION_TYPE_NONE;
         break;
+
+    default:
+        if (wire->type < ACTION_TYPE_PRIVATE) {
+            action->type = ACTION_TYPE_NONE;
+            break;
+        }
+
+        /* Treat high unknown actions as Private actions. */
+        action->priv.type = wire->noaction.type;
+        STATIC_ASSERT(sizeof(action->priv.data) == 7 &&
+                      sizeof(wire->noaction.pad0) == 7,
+                      "The private action data must be 7 bytes long!");
+        memcpy(action->priv.data, wire->noaction.pad0, 7);
+        break;
     }
 }
 
@@ -429,18 +471,19 @@ get_sym_maps(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
             FAIL_UNLESS((unsigned) syms_length == wire_sym_map->width * key->num_groups);
 
-            for (int j = 0; j < syms_length; j++) {
-                xcb_keysym_t wire_keysym = *syms_iter;
-                const xkb_layout_index_t group = j / wire_sym_map->width;
-                const xkb_level_index_t level = j % wire_sym_map->width;
+            for (xkb_layout_index_t group = 0; group < key->num_groups; group++) {
+                for (xkb_level_index_t level = 0; level < wire_sym_map->width; level++) {
+                    xcb_keysym_t wire_keysym = *syms_iter;
 
-                if (level < key->groups[group].type->num_levels &&
-                    wire_keysym != XKB_KEY_NoSymbol) {
-                    key->groups[group].levels[level].num_syms = 1;
-                    key->groups[group].levels[level].u.sym = wire_keysym;
-                }
+                    assert(key->groups[group].type != NULL);
+                    if (level < key->groups[group].type->num_levels &&
+                        wire_keysym != XKB_KEY_NoSymbol) {
+                        key->groups[group].levels[level].num_syms = 1;
+                        key->groups[group].levels[level].u.sym = wire_keysym;
+                    }
 
-                syms_iter++;
+                    syms_iter++;
+                }
             }
         }
 
@@ -475,21 +518,23 @@ get_actions(struct xkb_keymap *keymap, xcb_connection_t *conn,
         uint8_t wire_count = *acts_count_iter;
         struct xkb_key *key = &keymap->keys[reply->firstKeyAction + i];
 
+        FAIL_UNLESS((unsigned) syms_length == wire_sym_map->width * key->num_groups);
         FAIL_UNLESS(wire_count == 0 || wire_count == syms_length);
 
-        for (int j = 0; j < wire_count; j++) {
-            xcb_xkb_action_t *wire_action = acts_iter.data;
-            const xkb_layout_index_t group = j / wire_sym_map->width;
-            const xkb_level_index_t level = j % wire_sym_map->width;
+        if (wire_count != 0) {
+            for (xkb_layout_index_t group = 0; group < key->num_groups; group++) {
+                for (xkb_level_index_t level = 0; level < wire_sym_map->width; level++) {
+                    xcb_xkb_action_t *wire_action = acts_iter.data;
 
-            if (level < key->groups[group].type->num_levels) {
-                union xkb_action *action =
-                    &key->groups[group].levels[level].action;
+                    if (level < key->groups[group].type->num_levels) {
+                        union xkb_action *action = &key->groups[group].levels[level].action;
 
-                translate_action(action, wire_action);
-            }
+                        translate_action(action, wire_action);
+                    }
 
-            xcb_xkb_action_next(&acts_iter);
+                    xcb_xkb_action_next(&acts_iter);
+                }
+            }
         }
 
         acts_count_iter++;
@@ -508,13 +553,13 @@ get_vmods(struct xkb_keymap *keymap, xcb_connection_t *conn,
 {
     uint8_t *iter = xcb_xkb_get_map_map_vmods_rtrn(map);
 
-    darray_resize0(keymap->mods,
-                   NUM_REAL_MODS + msb_pos(reply->virtualMods));
+    keymap->mods.num_mods =
+        NUM_REAL_MODS + MIN(msb_pos(reply->virtualMods), NUM_VMODS);
 
     for (unsigned i = 0; i < NUM_VMODS; i++) {
         if (reply->virtualMods & (1u << i)) {
             uint8_t wire = *iter;
-            struct xkb_mod *mod = &darray_item(keymap->mods, NUM_REAL_MODS + i);
+            struct xkb_mod *mod = &keymap->mods.mods[NUM_REAL_MODS + i];
 
             mod->type = MOD_VIRT;
             mod->mapping = translate_mods(wire, 0, 0);
@@ -536,11 +581,13 @@ get_explicits(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
     for (int i = 0; i < length; i++) {
         xcb_xkb_set_explicit_t *wire = iter.data;
-        struct xkb_key *key = &keymap->keys[wire->keycode];
+        struct xkb_key *key;
 
         FAIL_UNLESS(wire->keycode >= keymap->min_key_code &&
                     wire->keycode <= keymap->max_key_code);
 
+        key = &keymap->keys[wire->keycode];
+
         if ((wire->explicit & XCB_XKB_EXPLICIT_KEY_TYPE_1) &&
             key->num_groups > 0)
             key->groups[0].explicit_type = true;
@@ -579,11 +626,12 @@ get_modmaps(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
     for (int i = 0; i < length; i++) {
         xcb_xkb_key_mod_map_t *wire = iter.data;
-        struct xkb_key *key = &keymap->keys[wire->keycode];
+        struct xkb_key *key;
 
         FAIL_UNLESS(wire->keycode >= keymap->min_key_code &&
                     wire->keycode <= keymap->max_key_code);
 
+        key = &keymap->keys[wire->keycode];
         key->modmap = wire->mods;
 
         xcb_xkb_key_mod_map_next(&iter);
@@ -605,11 +653,12 @@ get_vmodmaps(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
     for (int i = 0; i < length; i++) {
         xcb_xkb_key_v_mod_map_t *wire = iter.data;
-        struct xkb_key *key = &keymap->keys[wire->keycode];
+        struct xkb_key *key;
 
         FAIL_UNLESS(wire->keycode >= keymap->min_key_code &&
                     wire->keycode <= keymap->max_key_code);
 
+        key = &keymap->keys[wire->keycode];
         key->vmodmap = translate_mods(0, wire->vmods, 0);
 
         xcb_xkb_key_v_mod_map_next(&iter);
@@ -622,26 +671,15 @@ fail:
 }
 
 static bool
-get_map(struct xkb_keymap *keymap, xcb_connection_t *conn, uint16_t device_id)
+get_map(struct xkb_keymap *keymap, xcb_connection_t *conn,
+        xcb_xkb_get_map_cookie_t cookie)
 {
-    static const xcb_xkb_map_part_t required_components =
-        (XCB_XKB_MAP_PART_KEY_TYPES |
-         XCB_XKB_MAP_PART_KEY_SYMS |
-         XCB_XKB_MAP_PART_MODIFIER_MAP |
-         XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
-         XCB_XKB_MAP_PART_KEY_ACTIONS |
-         XCB_XKB_MAP_PART_VIRTUAL_MODS |
-         XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
-
-    xcb_xkb_get_map_cookie_t cookie =
-        xcb_xkb_get_map(conn, device_id, required_components,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
     xcb_xkb_get_map_reply_t *reply = xcb_xkb_get_map_reply(conn, cookie, NULL);
     xcb_xkb_get_map_map_t map;
 
     FAIL_IF_BAD_REPLY(reply, "XkbGetMap");
 
-    if ((reply->present & required_components) != required_components)
+    if ((reply->present & get_map_required_components) != get_map_required_components)
         goto fail;
 
     xcb_xkb_get_map_map_unpack(xcb_xkb_get_map_map(reply),
@@ -681,12 +719,12 @@ get_indicators(struct xkb_keymap *keymap, xcb_connection_t *conn,
     xcb_xkb_indicator_map_iterator_t iter =
         xcb_xkb_get_indicator_map_maps_iterator(reply);
 
-    darray_resize0(keymap->leds, msb_pos(reply->which));
+    keymap->num_leds = msb_pos(reply->which);
 
     for (unsigned i = 0; i < NUM_INDICATORS; i++) {
         if (reply->which & (1u << i)) {
             xcb_xkb_indicator_map_t *wire = iter.data;
-            struct xkb_led *led = &darray_item(keymap->leds, i);
+            struct xkb_led *led = &keymap->leds[i];
 
             if (wire->whichGroups & XCB_XKB_IM_GROUPS_WHICH_USE_BASE)
                 led->which_groups |= XKB_STATE_LAYOUT_DEPRESSED;
@@ -726,10 +764,8 @@ get_indicators(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
 static bool
 get_indicator_map(struct xkb_keymap *keymap, xcb_connection_t *conn,
-                  uint16_t device_id)
+                  xcb_xkb_get_indicator_map_cookie_t cookie)
 {
-    xcb_xkb_get_indicator_map_cookie_t cookie =
-        xcb_xkb_get_indicator_map(conn, device_id, ALL_INDICATORS_MASK);
     xcb_xkb_get_indicator_map_reply_t *reply =
         xcb_xkb_get_indicator_map_reply(conn, cookie, NULL);
 
@@ -785,7 +821,7 @@ get_sym_interprets(struct xkb_keymap *keymap, xcb_connection_t *conn,
         }
 
         sym_interpret->level_one_only =
-            !!(wire->match & XCB_XKB_SYM_INTERP_MATCH_LEVEL_ONE_ONLY);
+            (wire->match & XCB_XKB_SYM_INTERP_MATCH_LEVEL_ONE_ONLY);
         sym_interpret->mods = wire->mods;
 
         if (wire->virtualMod == NO_MODIFIER)
@@ -793,7 +829,7 @@ get_sym_interprets(struct xkb_keymap *keymap, xcb_connection_t *conn,
         else
             sym_interpret->virtual_mod = NUM_REAL_MODS + wire->virtualMod;
 
-        sym_interpret->repeat = !!(wire->flags & 0x01);
+        sym_interpret->repeat = (wire->flags & 0x01);
         translate_action(&sym_interpret->action,
                          (xcb_xkb_action_t *) &wire->action);
 
@@ -808,10 +844,8 @@ fail:
 
 static bool
 get_compat_map(struct xkb_keymap *keymap, xcb_connection_t *conn,
-               uint16_t device_id)
+               xcb_xkb_get_compat_map_cookie_t cookie)
 {
-    xcb_xkb_get_compat_map_cookie_t cookie =
-        xcb_xkb_get_compat_map(conn, device_id, 0, true, 0, 0);
     xcb_xkb_get_compat_map_reply_t *reply =
         xcb_xkb_get_compat_map_reply(conn, cookie, NULL);
 
@@ -829,7 +863,7 @@ fail:
 }
 
 static bool
-get_type_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
+get_type_names(struct xkb_keymap *keymap, struct x11_atom_interner *interner,
                xcb_xkb_get_names_reply_t *reply,
                xcb_xkb_get_names_value_list_t *list)
 {
@@ -857,14 +891,13 @@ get_type_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
 
         ALLOC_OR_FAIL(type->level_names, type->num_levels);
 
-        if (!adopt_atom(keymap->ctx, conn, wire_type_name, &type->name))
-            goto fail;
-
-        if (!adopt_atoms(keymap->ctx, conn,
-                         kt_level_names_iter, type->level_names,
-                         wire_num_levels))
-            goto fail;
+        x11_atom_interner_adopt_atom(interner, wire_type_name, &type->name);
+        for (size_t j = 0; j < wire_num_levels; j++) {
+            x11_atom_interner_adopt_atom(interner, kt_level_names_iter[j],
+                                         &type->level_names[j]);
+        }
 
+        type->num_level_names = type->num_levels;
         kt_level_names_iter += wire_num_levels;
         key_type_names_iter++;
         n_levels_per_type_iter++;
@@ -877,21 +910,21 @@ fail:
 }
 
 static bool
-get_indicator_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
+get_indicator_names(struct xkb_keymap *keymap,
+                    struct x11_atom_interner *interner,
                     xcb_xkb_get_names_reply_t *reply,
                     xcb_xkb_get_names_value_list_t *list)
 {
     xcb_atom_t *iter = xcb_xkb_get_names_value_list_indicator_names(list);
 
-    FAIL_UNLESS(msb_pos(reply->indicators) <= darray_size(keymap->leds));
+    FAIL_UNLESS(msb_pos(reply->indicators) <= keymap->num_leds);
 
     for (unsigned i = 0; i < NUM_INDICATORS; i++) {
         if (reply->indicators & (1u << i)) {
             xcb_atom_t wire = *iter;
-            struct xkb_led *led = &darray_item(keymap->leds, i);
+            struct xkb_led *led = &keymap->leds[i];
 
-            if (!adopt_atom(keymap->ctx, conn, wire, &led->name))
-                return false;
+            x11_atom_interner_adopt_atom(interner, wire, &led->name);
 
             iter++;
         }
@@ -904,7 +937,7 @@ fail:
 }
 
 static bool
-get_vmod_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
+get_vmod_names(struct xkb_keymap *keymap, struct x11_atom_interner *interner,
                xcb_xkb_get_names_reply_t *reply,
                xcb_xkb_get_names_value_list_t *list)
 {
@@ -915,15 +948,15 @@ get_vmod_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
      * tells us which vmods exist (a vmod must have a name), so we fix
      * up the size here.
      */
-    darray_resize0(keymap->mods, NUM_REAL_MODS + msb_pos(reply->virtualMods));
+    keymap->mods.num_mods =
+        NUM_REAL_MODS + MIN(msb_pos(reply->virtualMods), NUM_VMODS);
 
     for (unsigned i = 0; i < NUM_VMODS; i++) {
         if (reply->virtualMods & (1u << i)) {
             xcb_atom_t wire = *iter;
-            struct xkb_mod *mod = &darray_item(keymap->mods, NUM_REAL_MODS + i);
+            struct xkb_mod *mod = &keymap->mods.mods[NUM_REAL_MODS + i];
 
-            if (!adopt_atom(keymap->ctx, conn, wire, &mod->name))
-                return false;
+            x11_atom_interner_adopt_atom(interner, wire, &mod->name);
 
             iter++;
         }
@@ -933,7 +966,7 @@ get_vmod_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
 }
 
 static bool
-get_group_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
+get_group_names(struct xkb_keymap *keymap, struct x11_atom_interner *interner,
                 xcb_xkb_get_names_reply_t *reply,
                 xcb_xkb_get_names_value_list_t *list)
 {
@@ -943,9 +976,10 @@ get_group_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
     keymap->num_group_names = msb_pos(reply->groupNames);
     ALLOC_OR_FAIL(keymap->group_names, keymap->num_group_names);
 
-    if (!adopt_atoms(keymap->ctx, conn,
-                     iter, keymap->group_names, length))
-        goto fail;
+    for (int i = 0; i < length; i++) {
+        x11_atom_interner_adopt_atom(interner, iter[i],
+                                     &keymap->group_names[i]);
+    }
 
     return true;
 
@@ -1026,32 +1060,17 @@ fail:
 }
 
 static bool
-get_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
-          uint16_t device_id)
+get_names(struct xkb_keymap *keymap, struct x11_atom_interner *interner,
+          xcb_xkb_get_names_cookie_t cookie)
 {
-    static const xcb_xkb_name_detail_t required_names =
-        (XCB_XKB_NAME_DETAIL_KEYCODES |
-         XCB_XKB_NAME_DETAIL_SYMBOLS |
-         XCB_XKB_NAME_DETAIL_TYPES |
-         XCB_XKB_NAME_DETAIL_COMPAT |
-         XCB_XKB_NAME_DETAIL_KEY_TYPE_NAMES |
-         XCB_XKB_NAME_DETAIL_KT_LEVEL_NAMES |
-         XCB_XKB_NAME_DETAIL_INDICATOR_NAMES |
-         XCB_XKB_NAME_DETAIL_KEY_NAMES |
-         XCB_XKB_NAME_DETAIL_KEY_ALIASES |
-         XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES |
-         XCB_XKB_NAME_DETAIL_GROUP_NAMES);
-
-    xcb_xkb_get_names_cookie_t cookie =
-        xcb_xkb_get_names(conn, device_id, required_names);
+    xcb_connection_t *conn = interner->conn;
     xcb_xkb_get_names_reply_t *reply =
         xcb_xkb_get_names_reply(conn, cookie, NULL);
     xcb_xkb_get_names_value_list_t list;
 
     FAIL_IF_BAD_REPLY(reply, "XkbGetNames");
 
-    if ((reply->which & required_names) != required_names)
-        goto fail;
+    FAIL_UNLESS((reply->which & get_names_required) == get_names_required);
 
     xcb_xkb_get_names_value_list_unpack(xcb_xkb_get_names_value_list(reply),
                                         reply->nTypes,
@@ -1064,23 +1083,22 @@ get_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
                                         reply->which,
                                         &list);
 
-    if (!get_atom_name(conn, list.keycodesName, &keymap->keycodes_section_name) ||
-        !get_atom_name(conn, list.symbolsName, &keymap->symbols_section_name) ||
-        !get_atom_name(conn, list.typesName, &keymap->types_section_name) ||
-        !get_atom_name(conn, list.compatName, &keymap->compat_section_name) ||
-        !get_type_names(keymap, conn, reply, &list) ||
-        !get_indicator_names(keymap, conn, reply, &list) ||
-        !get_vmod_names(keymap, conn, reply, &list) ||
-        !get_group_names(keymap, conn, reply, &list) ||
+    x11_atom_interner_get_escaped_atom_name(interner, list.keycodesName,
+                                            &keymap->keycodes_section_name);
+    x11_atom_interner_get_escaped_atom_name(interner, list.symbolsName,
+                                            &keymap->symbols_section_name);
+    x11_atom_interner_get_escaped_atom_name(interner, list.typesName,
+                                            &keymap->types_section_name);
+    x11_atom_interner_get_escaped_atom_name(interner, list.compatName,
+                                            &keymap->compat_section_name);
+    if (!get_type_names(keymap, interner, reply, &list) ||
+        !get_indicator_names(keymap, interner, reply, &list) ||
+        !get_vmod_names(keymap, interner, reply, &list) ||
+        !get_group_names(keymap, interner, reply, &list) ||
         !get_key_names(keymap, conn, reply, &list) ||
         !get_aliases(keymap, conn, reply, &list))
         goto fail;
 
-    XkbEscapeMapName(keymap->keycodes_section_name);
-    XkbEscapeMapName(keymap->symbols_section_name);
-    XkbEscapeMapName(keymap->types_section_name);
-    XkbEscapeMapName(keymap->compat_section_name);
-
     free(reply);
     return true;
 
@@ -1091,14 +1109,13 @@ fail:
 
 static bool
 get_controls(struct xkb_keymap *keymap, xcb_connection_t *conn,
-             uint16_t device_id)
+             xcb_xkb_get_controls_cookie_t cookie)
 {
-    xcb_xkb_get_controls_cookie_t cookie =
-        xcb_xkb_get_controls(conn, device_id);
     xcb_xkb_get_controls_reply_t *reply =
         xcb_xkb_get_controls_reply(conn, cookie, NULL);
 
     FAIL_IF_BAD_REPLY(reply, "XkbGetControls");
+    FAIL_UNLESS(reply->numGroups > 0 && reply->numGroups <= 4);
 
     keymap->enabled_ctrls = translate_controls_mask(reply->enabledControls);
     keymap->num_groups = reply->numGroups;
@@ -1106,7 +1123,7 @@ get_controls(struct xkb_keymap *keymap, xcb_connection_t *conn,
     FAIL_UNLESS(keymap->max_key_code < XCB_XKB_CONST_PER_KEY_BIT_ARRAY_SIZE * 8);
 
     for (xkb_keycode_t i = keymap->min_key_code; i <= keymap->max_key_code; i++)
-        keymap->keys[i].repeats = !!(reply->perKeyRepeat[i / 8] & (1 << (i % 8)));
+        keymap->keys[i].repeats = (reply->perKeyRepeat[i / 8] & (1 << (i % 8)));
 
     free(reply);
     return true;
@@ -1130,7 +1147,7 @@ xkb_x11_keymap_new_from_device(struct xkb_context *ctx,
         return NULL;
     }
 
-    if (device_id < 0 || device_id > 255) {
+    if (device_id < 0 || device_id > 127) {
         log_err_func(ctx, "illegal device ID: %d\n", device_id);
         return NULL;
     }
@@ -1139,14 +1156,52 @@ xkb_x11_keymap_new_from_device(struct xkb_context *ctx,
     if (!keymap)
         return NULL;
 
-    if (!get_map(keymap, conn, device_id) ||
-        !get_indicator_map(keymap, conn, device_id) ||
-        !get_compat_map(keymap, conn, device_id) ||
-        !get_names(keymap, conn, device_id) ||
-        !get_controls(keymap, conn, device_id)) {
-        xkb_keymap_unref(keymap);
-        return NULL;
-    }
+    struct x11_atom_interner interner;
+    x11_atom_interner_init(&interner, ctx, conn);
+
+    /*
+     * Send all requests together so only one roundtrip is needed
+     * to get the replies.
+     */
+    xcb_xkb_get_map_cookie_t map_cookie =
+        xcb_xkb_get_map(conn, device_id, get_map_required_components,
+                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    xcb_xkb_get_indicator_map_cookie_t indicator_map_cookie =
+        xcb_xkb_get_indicator_map(conn, device_id, ALL_INDICATORS_MASK);
+    xcb_xkb_get_compat_map_cookie_t compat_map_cookie =
+        xcb_xkb_get_compat_map(conn, device_id, 0, true, 0, 0);
+    xcb_xkb_get_names_cookie_t names_cookie =
+        xcb_xkb_get_names(conn, device_id, get_names_wanted);
+    xcb_xkb_get_controls_cookie_t controls_cookie =
+        xcb_xkb_get_controls(conn, device_id);
+
+    if (!get_map(keymap, conn, map_cookie))
+        goto err_map;
+    if (!get_indicator_map(keymap, conn, indicator_map_cookie))
+        goto err_indicator_map;
+    if (!get_compat_map(keymap, conn, compat_map_cookie))
+        goto err_compat_map;
+    if (!get_names(keymap, &interner, names_cookie))
+        goto err_names;
+    if (!get_controls(keymap, conn, controls_cookie))
+        goto err_controls;
+    x11_atom_interner_round_trip(&interner);
+    if (interner.had_error)
+        goto err_interner;
 
     return keymap;
+
+err_map:
+    xcb_discard_reply(conn, indicator_map_cookie.sequence);
+err_indicator_map:
+    xcb_discard_reply(conn, compat_map_cookie.sequence);
+err_compat_map:
+    xcb_discard_reply(conn, names_cookie.sequence);
+err_names:
+    xcb_discard_reply(conn, controls_cookie.sequence);
+err_controls:
+    x11_atom_interner_round_trip(&interner);
+err_interner:
+    xkb_keymap_unref(keymap);
+    return NULL;
 }