glfw: Certain applications crash on wlroots compositors with: XDG surface must not have a buffer at creation

Hello,

When trying to run kitty as a native Wayland application, I ran into the following error: https://github.com/kovidgoyal/kitty/issues/157#issuecomment-389390996 , namely

wl_surface@13: error 3: xdg_surface must not have a buffer at creation
[135 23:29:00.699834] [glfw error 65544]: Wayland: Focusing a window requires user interaction
[135 23:29:00.699870] [glfw error 65544]: Wayland: Window position retrieval not supported

It seems that kitty and perhaps other apps using glfw for rendering allow the creation of a surface which already has a buffer attached, which is not allowed. For example, the sway window manager throws an error when launching kitty (https://github.com/swaywm/sway/issues/1992). Although kitty uses a patched version of glfw, the changes only pertain to some keyboard handling and I don’t believe that is the source of the issue. I would appreciate any help - this is far from my area of expertise, so let me know if there is any other information I can provide that would be useful.

Thank you!

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 33 (27 by maintainers)

Commits related to this issue

Most upvoted comments

@aenda Here is a workaround in kitty for this bug: https://github.com/kovidgoyal/kitty/commit/567cd163d9e66c383b659aee0e359a08f37fa1b0

With it, kitty works with wlrootston. Note that it is against the refactor branch not master.

Yup, this bug is nothing kitty specific, withthe follwoing two line patch to examples/simple.c it fails with glfw/master.

diff --git a/examples/simple.c b/examples/simple.c
index 7752a365..0e38f4e8 100644
--- a/examples/simple.c
+++ b/examples/simple.c
@@ -87,6 +87,7 @@ int main(void)
 
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
 
     window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
     if (!window)
@@ -94,6 +95,7 @@ int main(void)
         glfwTerminate();
         exit(EXIT_FAILURE);
     }
+    glfwShowWindow(window);
 
     glfwSetKeyCallback(window, key_callback);

Let me emphasize that this fails on unmodified glfw. And it means that the glfw wayland backend makes it impossible to create windows without showing them simulataneously.

So this is a downstream error, please get in touch with the Kitty developers and ask them to update their internal fork of GLFW. The focusing warning is expected, it isn’t possible on Wayland to force-focus a window.

@kovidgoyal, there is only one glfwCreateWindow() function, and it must always do the correct thing.

Just for completeness, here is a diff of the wl_* files in glfw master vs kitty, as you can see the only changes are related to keyboard handling and so cannot have a bearing on this issue.

Diff of upstream vs kitty GLFW
diff -Naurp /t/g/wl_init.c /t/k/wl_init.c
--- /t/g/wl_init.c	2018-05-20 08:20:32.313078050 +0530
+++ /t/k/wl_init.c	2018-05-20 08:19:09.523787242 +0530
@@ -32,7 +32,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
-#include <sys/timerfd.h>
 #include <unistd.h>
 #include <wayland-client.h>
 
@@ -350,16 +349,7 @@ static void keyboardHandleKeymap(void* d
                                  int fd,
                                  uint32_t size)
 {
-    struct xkb_keymap* keymap;
-    struct xkb_state* state;
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-    struct xkb_compose_table* composeTable;
-    struct xkb_compose_state* composeState;
-#endif
-
     char* mapStr;
-    const char* locale;
 
     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
     {
@@ -372,78 +362,10 @@ static void keyboardHandleKeymap(void* d
         close(fd);
         return;
     }
-
-    keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
-                                        mapStr,
-                                        XKB_KEYMAP_FORMAT_TEXT_V1,
-                                        0);
+    glfw_xkb_compile_keymap(&_glfw.wl.xkb, mapStr);
     munmap(mapStr, size);
     close(fd);
 
-    if (!keymap)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to compile keymap");
-        return;
-    }
-
-    state = xkb_state_new(keymap);
-    if (!state)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to create XKB state");
-        xkb_keymap_unref(keymap);
-        return;
-    }
-
-    // Look up the preferred locale, falling back to "C" as default.
-    locale = getenv("LC_ALL");
-    if (!locale)
-        locale = getenv("LC_CTYPE");
-    if (!locale)
-        locale = getenv("LANG");
-    if (!locale)
-        locale = "C";
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-    composeTable =
-        xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
-                                          XKB_COMPOSE_COMPILE_NO_FLAGS);
-    if (composeTable)
-    {
-        composeState =
-            xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
-        xkb_compose_table_unref(composeTable);
-        if (composeState)
-            _glfw.wl.xkb.composeState = composeState;
-        else
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "Wayland: Failed to create XKB compose state");
-    }
-    else
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to create XKB compose table");
-    }
-#endif
-
-    xkb_keymap_unref(_glfw.wl.xkb.keymap);
-    xkb_state_unref(_glfw.wl.xkb.state);
-    _glfw.wl.xkb.keymap = keymap;
-    _glfw.wl.xkb.state = state;
-
-    _glfw.wl.xkb.controlMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
-    _glfw.wl.xkb.altMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
-    _glfw.wl.xkb.shiftMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
-    _glfw.wl.xkb.superMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
-    _glfw.wl.xkb.capsLockMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
-    _glfw.wl.xkb.numLockMask =
-        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
 }
 
 static void keyboardHandleEnter(void* data,
@@ -482,65 +404,6 @@ static void keyboardHandleLeave(void* da
     _glfwInputWindowFocus(window, GLFW_FALSE);
 }
 
-static int toGLFWKeyCode(uint32_t key)
-{
-    if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
-        return _glfw.wl.keycodes[key];
-
-    return GLFW_KEY_UNKNOWN;
-}
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
-{
-    if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
-        return sym;
-    if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
-            != XKB_COMPOSE_FEED_ACCEPTED)
-        return sym;
-    switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
-    {
-        case XKB_COMPOSE_COMPOSED:
-            return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
-        case XKB_COMPOSE_COMPOSING:
-        case XKB_COMPOSE_CANCELLED:
-            return XKB_KEY_NoSymbol;
-        case XKB_COMPOSE_NOTHING:
-        default:
-            return sym;
-    }
-}
-#endif
-
-static GLFWbool inputChar(_GLFWwindow* window, uint32_t key)
-{
-    uint32_t code, numSyms;
-    long cp;
-    const xkb_keysym_t *syms;
-    xkb_keysym_t sym;
-
-    code = key + 8;
-    numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms);
-
-    if (numSyms == 1)
-    {
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-        sym = composeSymbol(syms[0]);
-#else
-        sym = syms[0];
-#endif
-        cp = _glfwKeySym2Unicode(sym);
-        if (cp != -1)
-        {
-            const int mods = _glfw.wl.xkb.modifiers;
-            const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
-            _glfwInputChar(window, cp, mods, plain);
-        }
-    }
-
-    return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]);
-}
-
 static void keyboardHandleKey(void* data,
                               struct wl_keyboard* keyboard,
                               uint32_t serial,
@@ -548,37 +411,19 @@ static void keyboardHandleKey(void* data
                               uint32_t key,
                               uint32_t state)
 {
-    int keyCode;
-    int action;
     _GLFWwindow* window = _glfw.wl.keyboardFocus;
-    GLFWbool shouldRepeat;
-    struct itimerspec timer = {};
-
     if (!window)
         return;
-
-    keyCode = toGLFWKeyCode(key);
-    action = state == WL_KEYBOARD_KEY_STATE_PRESSED
-            ? GLFW_PRESS : GLFW_RELEASE;
-
-    _glfwInputKey(window, keyCode, key, action,
-                  _glfw.wl.xkb.modifiers);
-
-    if (action == GLFW_PRESS)
-    {
-        shouldRepeat = inputChar(window, key);
-
-        if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
-        {
-            _glfw.wl.keyboardLastKey = keyCode;
-            _glfw.wl.keyboardLastScancode = key;
-            timer.it_interval.tv_sec = _glfw.wl.keyboardRepeatRate / 1000;
-            timer.it_interval.tv_nsec = (_glfw.wl.keyboardRepeatRate % 1000) * 1000000;
-            timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;
-            timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;
-        }
+    int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
+    glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
+    _glfw.wl.keyRepeatInfo.nextRepeatAt = 0;
+
+    if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
+    {
+        _glfw.wl.keyRepeatInfo.key = key;
+        _glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0;
+        _glfw.wl.keyRepeatInfo.keyboardFocus = window;
     }
-    timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
 }
 
 static void keyboardHandleModifiers(void* data,
@@ -589,41 +434,9 @@ static void keyboardHandleModifiers(void
                                     uint32_t modsLocked,
                                     uint32_t group)
 {
-    xkb_mod_mask_t mask;
-    unsigned int modifiers = 0;
-
-    if (!_glfw.wl.xkb.keymap)
-        return;
-
-    xkb_state_update_mask(_glfw.wl.xkb.state,
-                          modsDepressed,
-                          modsLatched,
-                          modsLocked,
-                          0,
-                          0,
-                          group);
-
-    mask = xkb_state_serialize_mods(_glfw.wl.xkb.state,
-                                    XKB_STATE_MODS_DEPRESSED |
-                                    XKB_STATE_LAYOUT_DEPRESSED |
-                                    XKB_STATE_MODS_LATCHED |
-                                    XKB_STATE_LAYOUT_LATCHED);
-    if (mask & _glfw.wl.xkb.controlMask)
-        modifiers |= GLFW_MOD_CONTROL;
-    if (mask & _glfw.wl.xkb.altMask)
-        modifiers |= GLFW_MOD_ALT;
-    if (mask & _glfw.wl.xkb.shiftMask)
-        modifiers |= GLFW_MOD_SHIFT;
-    if (mask & _glfw.wl.xkb.superMask)
-        modifiers |= GLFW_MOD_SUPER;
-    if (mask & _glfw.wl.xkb.capsLockMask)
-        modifiers |= GLFW_MOD_CAPS_LOCK;
-    if (mask & _glfw.wl.xkb.numLockMask)
-        modifiers |= GLFW_MOD_NUM_LOCK;
-    _glfw.wl.xkb.modifiers = modifiers;
+    glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
 }
 
-#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
 static void keyboardHandleRepeatInfo(void* data,
                                      struct wl_keyboard* keyboard,
                                      int32_t rate,
@@ -635,7 +448,6 @@ static void keyboardHandleRepeatInfo(voi
     _glfw.wl.keyboardRepeatRate = rate;
     _glfw.wl.keyboardRepeatDelay = delay;
 }
-#endif
 
 static const struct wl_keyboard_listener keyboardListener = {
     keyboardHandleKeymap,
@@ -643,9 +455,7 @@ static const struct wl_keyboard_listener
     keyboardHandleLeave,
     keyboardHandleKey,
     keyboardHandleModifiers,
-#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
     keyboardHandleRepeatInfo,
-#endif
 };
 
 static void seatHandleCapabilities(void* data,
@@ -798,140 +608,6 @@ static const struct wl_registry_listener
     registryHandleGlobalRemove
 };
 
-// Create key code translation tables
-//
-static void createKeyTables(void)
-{
-    int scancode;
-
-    memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes));
-    memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes));
-
-    _glfw.wl.keycodes[KEY_GRAVE]      = GLFW_KEY_GRAVE_ACCENT;
-    _glfw.wl.keycodes[KEY_1]          = GLFW_KEY_1;
-    _glfw.wl.keycodes[KEY_2]          = GLFW_KEY_2;
-    _glfw.wl.keycodes[KEY_3]          = GLFW_KEY_3;
-    _glfw.wl.keycodes[KEY_4]          = GLFW_KEY_4;
-    _glfw.wl.keycodes[KEY_5]          = GLFW_KEY_5;
-    _glfw.wl.keycodes[KEY_6]          = GLFW_KEY_6;
-    _glfw.wl.keycodes[KEY_7]          = GLFW_KEY_7;
-    _glfw.wl.keycodes[KEY_8]          = GLFW_KEY_8;
-    _glfw.wl.keycodes[KEY_9]          = GLFW_KEY_9;
-    _glfw.wl.keycodes[KEY_0]          = GLFW_KEY_0;
-    _glfw.wl.keycodes[KEY_SPACE]      = GLFW_KEY_SPACE;
-    _glfw.wl.keycodes[KEY_MINUS]      = GLFW_KEY_MINUS;
-    _glfw.wl.keycodes[KEY_EQUAL]      = GLFW_KEY_EQUAL;
-    _glfw.wl.keycodes[KEY_Q]          = GLFW_KEY_Q;
-    _glfw.wl.keycodes[KEY_W]          = GLFW_KEY_W;
-    _glfw.wl.keycodes[KEY_E]          = GLFW_KEY_E;
-    _glfw.wl.keycodes[KEY_R]          = GLFW_KEY_R;
-    _glfw.wl.keycodes[KEY_T]          = GLFW_KEY_T;
-    _glfw.wl.keycodes[KEY_Y]          = GLFW_KEY_Y;
-    _glfw.wl.keycodes[KEY_U]          = GLFW_KEY_U;
-    _glfw.wl.keycodes[KEY_I]          = GLFW_KEY_I;
-    _glfw.wl.keycodes[KEY_O]          = GLFW_KEY_O;
-    _glfw.wl.keycodes[KEY_P]          = GLFW_KEY_P;
-    _glfw.wl.keycodes[KEY_LEFTBRACE]  = GLFW_KEY_LEFT_BRACKET;
-    _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
-    _glfw.wl.keycodes[KEY_A]          = GLFW_KEY_A;
-    _glfw.wl.keycodes[KEY_S]          = GLFW_KEY_S;
-    _glfw.wl.keycodes[KEY_D]          = GLFW_KEY_D;
-    _glfw.wl.keycodes[KEY_F]          = GLFW_KEY_F;
-    _glfw.wl.keycodes[KEY_G]          = GLFW_KEY_G;
-    _glfw.wl.keycodes[KEY_H]          = GLFW_KEY_H;
-    _glfw.wl.keycodes[KEY_J]          = GLFW_KEY_J;
-    _glfw.wl.keycodes[KEY_K]          = GLFW_KEY_K;
-    _glfw.wl.keycodes[KEY_L]          = GLFW_KEY_L;
-    _glfw.wl.keycodes[KEY_SEMICOLON]  = GLFW_KEY_SEMICOLON;
-    _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
-    _glfw.wl.keycodes[KEY_Z]          = GLFW_KEY_Z;
-    _glfw.wl.keycodes[KEY_X]          = GLFW_KEY_X;
-    _glfw.wl.keycodes[KEY_C]          = GLFW_KEY_C;
-    _glfw.wl.keycodes[KEY_V]          = GLFW_KEY_V;
-    _glfw.wl.keycodes[KEY_B]          = GLFW_KEY_B;
-    _glfw.wl.keycodes[KEY_N]          = GLFW_KEY_N;
-    _glfw.wl.keycodes[KEY_M]          = GLFW_KEY_M;
-    _glfw.wl.keycodes[KEY_COMMA]      = GLFW_KEY_COMMA;
-    _glfw.wl.keycodes[KEY_DOT]        = GLFW_KEY_PERIOD;
-    _glfw.wl.keycodes[KEY_SLASH]      = GLFW_KEY_SLASH;
-    _glfw.wl.keycodes[KEY_BACKSLASH]  = GLFW_KEY_BACKSLASH;
-    _glfw.wl.keycodes[KEY_ESC]        = GLFW_KEY_ESCAPE;
-    _glfw.wl.keycodes[KEY_TAB]        = GLFW_KEY_TAB;
-    _glfw.wl.keycodes[KEY_LEFTSHIFT]  = GLFW_KEY_LEFT_SHIFT;
-    _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
-    _glfw.wl.keycodes[KEY_LEFTCTRL]   = GLFW_KEY_LEFT_CONTROL;
-    _glfw.wl.keycodes[KEY_RIGHTCTRL]  = GLFW_KEY_RIGHT_CONTROL;
-    _glfw.wl.keycodes[KEY_LEFTALT]    = GLFW_KEY_LEFT_ALT;
-    _glfw.wl.keycodes[KEY_RIGHTALT]   = GLFW_KEY_RIGHT_ALT;
-    _glfw.wl.keycodes[KEY_LEFTMETA]   = GLFW_KEY_LEFT_SUPER;
-    _glfw.wl.keycodes[KEY_RIGHTMETA]  = GLFW_KEY_RIGHT_SUPER;
-    _glfw.wl.keycodes[KEY_MENU]       = GLFW_KEY_MENU;
-    _glfw.wl.keycodes[KEY_NUMLOCK]    = GLFW_KEY_NUM_LOCK;
-    _glfw.wl.keycodes[KEY_CAPSLOCK]   = GLFW_KEY_CAPS_LOCK;
-    _glfw.wl.keycodes[KEY_PRINT]      = GLFW_KEY_PRINT_SCREEN;
-    _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
-    _glfw.wl.keycodes[KEY_PAUSE]      = GLFW_KEY_PAUSE;
-    _glfw.wl.keycodes[KEY_DELETE]     = GLFW_KEY_DELETE;
-    _glfw.wl.keycodes[KEY_BACKSPACE]  = GLFW_KEY_BACKSPACE;
-    _glfw.wl.keycodes[KEY_ENTER]      = GLFW_KEY_ENTER;
-    _glfw.wl.keycodes[KEY_HOME]       = GLFW_KEY_HOME;
-    _glfw.wl.keycodes[KEY_END]        = GLFW_KEY_END;
-    _glfw.wl.keycodes[KEY_PAGEUP]     = GLFW_KEY_PAGE_UP;
-    _glfw.wl.keycodes[KEY_PAGEDOWN]   = GLFW_KEY_PAGE_DOWN;
-    _glfw.wl.keycodes[KEY_INSERT]     = GLFW_KEY_INSERT;
-    _glfw.wl.keycodes[KEY_LEFT]       = GLFW_KEY_LEFT;
-    _glfw.wl.keycodes[KEY_RIGHT]      = GLFW_KEY_RIGHT;
-    _glfw.wl.keycodes[KEY_DOWN]       = GLFW_KEY_DOWN;
-    _glfw.wl.keycodes[KEY_UP]         = GLFW_KEY_UP;
-    _glfw.wl.keycodes[KEY_F1]         = GLFW_KEY_F1;
-    _glfw.wl.keycodes[KEY_F2]         = GLFW_KEY_F2;
-    _glfw.wl.keycodes[KEY_F3]         = GLFW_KEY_F3;
-    _glfw.wl.keycodes[KEY_F4]         = GLFW_KEY_F4;
-    _glfw.wl.keycodes[KEY_F5]         = GLFW_KEY_F5;
-    _glfw.wl.keycodes[KEY_F6]         = GLFW_KEY_F6;
-    _glfw.wl.keycodes[KEY_F7]         = GLFW_KEY_F7;
-    _glfw.wl.keycodes[KEY_F8]         = GLFW_KEY_F8;
-    _glfw.wl.keycodes[KEY_F9]         = GLFW_KEY_F9;
-    _glfw.wl.keycodes[KEY_F10]        = GLFW_KEY_F10;
-    _glfw.wl.keycodes[KEY_F11]        = GLFW_KEY_F11;
-    _glfw.wl.keycodes[KEY_F12]        = GLFW_KEY_F12;
-    _glfw.wl.keycodes[KEY_F13]        = GLFW_KEY_F13;
-    _glfw.wl.keycodes[KEY_F14]        = GLFW_KEY_F14;
-    _glfw.wl.keycodes[KEY_F15]        = GLFW_KEY_F15;
-    _glfw.wl.keycodes[KEY_F16]        = GLFW_KEY_F16;
-    _glfw.wl.keycodes[KEY_F17]        = GLFW_KEY_F17;
-    _glfw.wl.keycodes[KEY_F18]        = GLFW_KEY_F18;
-    _glfw.wl.keycodes[KEY_F19]        = GLFW_KEY_F19;
-    _glfw.wl.keycodes[KEY_F20]        = GLFW_KEY_F20;
-    _glfw.wl.keycodes[KEY_F21]        = GLFW_KEY_F21;
-    _glfw.wl.keycodes[KEY_F22]        = GLFW_KEY_F22;
-    _glfw.wl.keycodes[KEY_F23]        = GLFW_KEY_F23;
-    _glfw.wl.keycodes[KEY_F24]        = GLFW_KEY_F24;
-    _glfw.wl.keycodes[KEY_KPSLASH]    = GLFW_KEY_KP_DIVIDE;
-    _glfw.wl.keycodes[KEY_KPDOT]      = GLFW_KEY_KP_MULTIPLY;
-    _glfw.wl.keycodes[KEY_KPMINUS]    = GLFW_KEY_KP_SUBTRACT;
-    _glfw.wl.keycodes[KEY_KPPLUS]     = GLFW_KEY_KP_ADD;
-    _glfw.wl.keycodes[KEY_KP0]        = GLFW_KEY_KP_0;
-    _glfw.wl.keycodes[KEY_KP1]        = GLFW_KEY_KP_1;
-    _glfw.wl.keycodes[KEY_KP2]        = GLFW_KEY_KP_2;
-    _glfw.wl.keycodes[KEY_KP3]        = GLFW_KEY_KP_3;
-    _glfw.wl.keycodes[KEY_KP4]        = GLFW_KEY_KP_4;
-    _glfw.wl.keycodes[KEY_KP5]        = GLFW_KEY_KP_5;
-    _glfw.wl.keycodes[KEY_KP6]        = GLFW_KEY_KP_6;
-    _glfw.wl.keycodes[KEY_KP7]        = GLFW_KEY_KP_7;
-    _glfw.wl.keycodes[KEY_KP8]        = GLFW_KEY_KP_8;
-    _glfw.wl.keycodes[KEY_KP9]        = GLFW_KEY_KP_9;
-    _glfw.wl.keycodes[KEY_KPCOMMA]    = GLFW_KEY_KP_DECIMAL;
-    _glfw.wl.keycodes[KEY_KPEQUAL]    = GLFW_KEY_KP_EQUAL;
-    _glfw.wl.keycodes[KEY_KPENTER]    = GLFW_KEY_KP_ENTER;
-
-    for (scancode = 0;  scancode < 256;  scancode++)
-    {
-        if (_glfw.wl.keycodes[scancode] > 0)
-            _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode;
-    }
-}
-
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
@@ -971,54 +647,6 @@ int _glfwPlatformInit(void)
     _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
         _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");
 
-    _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");
-    if (!_glfw.wl.xkb.handle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to open libxkbcommon");
-        return GLFW_FALSE;
-    }
-
-    _glfw.wl.xkb.context_new = (PFN_xkb_context_new)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");
-    _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");
-    _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");
-    _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");
-    _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");
-    _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");
-    _glfw.wl.xkb.state_new = (PFN_xkb_state_new)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");
-    _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");
-    _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");
-    _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");
-    _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-    _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");
-    _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");
-    _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");
-    _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");
-    _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");
-    _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
-    _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
-        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
-#endif
-
     _glfw.wl.display = wl_display_connect(NULL);
     if (!_glfw.wl.display)
     {
@@ -1030,15 +658,7 @@ int _glfwPlatformInit(void)
     _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
     wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
 
-    createKeyTables();
-
-    _glfw.wl.xkb.context = xkb_context_new(0);
-    if (!_glfw.wl.xkb.context)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to initialize xkb context");
-        return GLFW_FALSE;
-    }
+    if (!glfw_xkb_create_context(&_glfw.wl.xkb)) return GLFW_FALSE;
 
     // Sync so we got all registry objects
     wl_display_roundtrip(_glfw.wl.display);
@@ -1053,10 +673,6 @@ int _glfwPlatformInit(void)
 
     _glfwInitTimerPOSIX();
 
-    _glfw.wl.timerfd = -1;
-    if (_glfw.wl.seatVersion >= 4)
-        _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
-
     if (_glfw.wl.pointer && _glfw.wl.shm)
     {
         _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
@@ -1085,21 +701,7 @@ void _glfwPlatformTerminate(void)
         _glfw.wl.egl.handle = NULL;
     }
 
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-    if (_glfw.wl.xkb.composeState)
-        xkb_compose_state_unref(_glfw.wl.xkb.composeState);
-#endif
-    if (_glfw.wl.xkb.keymap)
-        xkb_keymap_unref(_glfw.wl.xkb.keymap);
-    if (_glfw.wl.xkb.state)
-        xkb_state_unref(_glfw.wl.xkb.state);
-    if (_glfw.wl.xkb.context)
-        xkb_context_unref(_glfw.wl.xkb.context);
-    if (_glfw.wl.xkb.handle)
-    {
-        _glfw_dlclose(_glfw.wl.xkb.handle);
-        _glfw.wl.xkb.handle = NULL;
-    }
+    glfw_xkb_release(&_glfw.wl.xkb);
 
     if (_glfw.wl.cursorTheme)
         wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
@@ -1158,4 +760,3 @@ const char* _glfwPlatformGetVersionStrin
 #endif
         ;
 }
-
diff -Naurp /t/g/wl_platform.h /t/k/wl_platform.h
--- /t/g/wl_platform.h	2018-05-20 08:20:32.313078050 +0530
+++ /t/k/wl_platform.h	2018-05-20 08:19:09.523787242 +0530
@@ -25,10 +25,6 @@
 //========================================================================
 
 #include <wayland-client.h>
-#include <xkbcommon/xkbcommon.h>
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-#include <xkbcommon/xkbcommon-compose.h>
-#endif
 #include <dlfcn.h>
 
 typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
@@ -52,7 +48,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhy
 #else
 #include "null_joystick.h"
 #endif
-#include "xkb_unicode.h"
+#include "xkb_glfw.h"
 #include "egl_context.h"
 #include "osmesa_context.h"
 
@@ -105,46 +101,6 @@ typedef void (* PFN_wl_egl_window_resize
 #define wl_egl_window_destroy _glfw.wl.egl.window_destroy
 #define wl_egl_window_resize _glfw.wl.egl.window_resize
 
-typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags);
-typedef void (* PFN_xkb_context_unref)(struct xkb_context*);
-typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
-typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*);
-typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*);
-typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t);
-typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*);
-typedef void (* PFN_xkb_state_unref)(struct xkb_state*);
-typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
-typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
-typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component);
-#define xkb_context_new _glfw.wl.xkb.context_new
-#define xkb_context_unref _glfw.wl.xkb.context_unref
-#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string
-#define xkb_keymap_unref _glfw.wl.xkb.keymap_unref
-#define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index
-#define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats
-#define xkb_state_new _glfw.wl.xkb.state_new
-#define xkb_state_unref _glfw.wl.xkb.state_unref
-#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms
-#define xkb_state_update_mask _glfw.wl.xkb.state_update_mask
-#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
-typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*);
-typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags);
-typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*);
-typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t);
-typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*);
-typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*);
-#define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale
-#define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref
-#define xkb_compose_state_new _glfw.wl.xkb.compose_state_new
-#define xkb_compose_state_unref _glfw.wl.xkb.compose_state_unref
-#define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed
-#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status
-#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
-#endif
-
 #define _GLFW_DECORATION_WIDTH 4
 #define _GLFW_DECORATION_TOP 24
 #define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
@@ -245,52 +201,12 @@ typedef struct _GLFWlibraryWayland
 
     int32_t                     keyboardRepeatRate;
     int32_t                     keyboardRepeatDelay;
-    int                         keyboardLastKey;
-    int                         keyboardLastScancode;
-    int                         timerfd;
-    short int                   keycodes[256];
-    short int                   scancodes[GLFW_KEY_LAST + 1];
-
     struct {
-        void*                   handle;
-        struct xkb_context*     context;
-        struct xkb_keymap*      keymap;
-        struct xkb_state*       state;
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-        struct xkb_compose_state* composeState;
-#endif
-
-        xkb_mod_mask_t          controlMask;
-        xkb_mod_mask_t          altMask;
-        xkb_mod_mask_t          shiftMask;
-        xkb_mod_mask_t          superMask;
-        xkb_mod_mask_t          capsLockMask;
-        xkb_mod_mask_t          numLockMask;
-        unsigned int            modifiers;
-
-        PFN_xkb_context_new context_new;
-        PFN_xkb_context_unref context_unref;
-        PFN_xkb_keymap_new_from_string keymap_new_from_string;
-        PFN_xkb_keymap_unref keymap_unref;
-        PFN_xkb_keymap_mod_get_index keymap_mod_get_index;
-        PFN_xkb_keymap_key_repeats keymap_key_repeats;
-        PFN_xkb_state_new state_new;
-        PFN_xkb_state_unref state_unref;
-        PFN_xkb_state_key_get_syms state_key_get_syms;
-        PFN_xkb_state_update_mask state_update_mask;
-        PFN_xkb_state_serialize_mods state_serialize_mods;
-
-#ifdef HAVE_XKBCOMMON_COMPOSE_H
-        PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
-        PFN_xkb_compose_table_unref compose_table_unref;
-        PFN_xkb_compose_state_new compose_state_new;
-        PFN_xkb_compose_state_unref compose_state_unref;
-        PFN_xkb_compose_state_feed compose_state_feed;
-        PFN_xkb_compose_state_get_status compose_state_get_status;
-        PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym;
-#endif
-    } xkb;
+        uint32_t                key;
+        double                  nextRepeatAt;
+        _GLFWwindow*            keyboardFocus;
+    } keyRepeatInfo;
+    _GLFWXKBData                xkb;
 
     _GLFWwindow*                pointerFocus;
     _GLFWwindow*                keyboardFocus;
@@ -340,4 +256,3 @@ typedef struct _GLFWcursorWayland
 
 
 void _glfwAddOutputWayland(uint32_t name, uint32_t version);
-
diff -Naurp /t/g/wl_window.c /t/k/wl_window.c
--- /t/g/wl_window.c	2018-05-20 08:20:32.313078050 +0530
+++ /t/k/wl_window.c	2018-05-20 08:19:09.523787242 +0530
@@ -35,7 +35,6 @@
 #include <string.h>
 #include <fcntl.h>
 #include <sys/mman.h>
-#include <sys/timerfd.h>
 #include <poll.h>
 
 
@@ -691,15 +690,31 @@ static GLFWbool createXdgSurface(_GLFWwi
 }
 
 static void
+dispatchPendingKeyRepeats() {
+    if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
+    double now = glfwGetTime();
+    while (_glfw.wl.keyRepeatInfo.nextRepeatAt <= now) {
+        glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
+        _glfw.wl.keyRepeatInfo.nextRepeatAt += 1.0 / _glfw.wl.keyboardRepeatRate;
+        now = glfwGetTime();
+    }
+}
+
+static int
+adjustTimeoutForKeyRepeat(int timeout) {
+    if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return timeout;
+    double now = glfwGetTime();
+    if (timeout < 0 || now + timeout / 1000. > _glfw.wl.keyRepeatInfo.nextRepeatAt) {
+        timeout = _glfw.wl.keyRepeatInfo.nextRepeatAt <= now ? 0 : ( (_glfw.wl.keyRepeatInfo.nextRepeatAt - now) * 1000 + 1 );
+    }
+    return timeout;
+}
+
+static void
 handleEvents(int timeout)
 {
     struct wl_display* display = _glfw.wl.display;
-    struct pollfd fds[] = {
-        { wl_display_get_fd(display), POLLIN },
-        { _glfw.wl.timerfd, POLLIN },
-    };
-    ssize_t read_ret;
-    uint64_t repeats, i;
+    struct pollfd pfd = { wl_display_get_fd(display), POLLIN };
 
     while (wl_display_prepare_read(display) != 0)
         wl_display_dispatch_pending(display);
@@ -719,9 +734,12 @@ handleEvents(int timeout)
         return;
     }
 
-    if (poll(fds, 2, timeout) > 0)
+    dispatchPendingKeyRepeats();
+    timeout = adjustTimeoutForKeyRepeat(timeout);
+
+    if (poll(&pfd, 1, timeout) > 0)
     {
-        if (fds[0].revents & POLLIN)
+        if (pfd.revents & POLLIN)
         {
             wl_display_read_events(display);
             wl_display_dispatch_pending(display);
@@ -731,22 +749,12 @@ handleEvents(int timeout)
             wl_display_cancel_read(display);
         }
 
-        if (fds[1].revents & POLLIN)
-        {
-            read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats));
-            if (read_ret != 8)
-                return;
-
-            for (i = 0; i < repeats; ++i)
-                _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey,
-                              _glfw.wl.keyboardLastScancode, GLFW_REPEAT,
-                              _glfw.wl.xkb.modifiers);
-        }
     }
     else
     {
         wl_display_cancel_read(display);
     }
+    dispatchPendingKeyRepeats();
 }
 
 // Translates a GLFW standard cursor to a theme cursor name
@@ -1079,6 +1087,18 @@ void _glfwPlatformRequestWindowAttention
                     "Wayland: Window attention request not implemented yet");
 }
 
+int _glfwPlatformWindowBell(_GLFWwindow* window)
+{
+    // TODO: Use an actual Wayland API to implement this when one becomes available
+    int fd = open("/dev/tty", O_WRONLY | O_CLOEXEC);
+    if (fd > -1) {
+        int ret = write(fd, "\x07", 1) == 1 ? GLFW_TRUE : GLFW_FALSE;
+        close(fd);
+        return ret;
+    }
+    return GLFW_FALSE;
+}
+
 void _glfwPlatformFocusWindow(_GLFWwindow* window)
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
@@ -1222,13 +1242,12 @@ void _glfwPlatformSetCursorMode(_GLFWwin
 
 const char* _glfwPlatformGetScancodeName(int scancode)
 {
-    // TODO
-    return NULL;
+    return glfw_xkb_keysym_name(scancode);
 }
 
 int _glfwPlatformGetKeyScancode(int key)
 {
-    return _glfw.wl.scancodes[key];
+    return glfw_xkb_sym_for_key(key);
 }
 
 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
@@ -1539,4 +1558,3 @@ GLFWAPI struct wl_surface* glfwGetWaylan
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return window->wl.surface;
 }
-