From f6c48afebee362af9aaedebe4e04fda616a9d1671681bee7afcb9cd23e326029 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Tue, 15 Apr 2014 05:34:07 +0000 Subject: [PATCH] Accepting request 229476 from KDE:Qt5 the fix for bnc#866051 and bnc#866709, the patches for bnc#866051 will part of Qt 5.3 but since it's important for on-the-fly keyboard layout remapping, should worth included them before 5.3 release. also change %suse_version to 1315 just because of current SLES12 use 1315 as its version number (forwarded request 229475 from mlin7442) OBS-URL: https://build.opensuse.org/request/show/229476 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libqt5-qtbase?expand=0&rev=17 --- ...r-support-for-keymap-update-handling.patch | 666 ++ libqt5-add-support-for-byte-swapping.patch | 122 + libqt5-byte-order-byte-is-address0.patch | 35 + libqt5-fix-build-failure-xcb.patch | 92 + libqt5-fix-regression-in-key-handling.patch | 86 + libqt5-improve-keymap-error-handling.patch | 158 + libqt5-qtbase.changes | 19 + libqt5-qtbase.spec | 32 +- ...-bundled-libxkbcommon-version-to-041.patch | 7085 +++++++++++++++++ 9 files changed, 8288 insertions(+), 7 deletions(-) create mode 100644 libqt5-add-better-support-for-keymap-update-handling.patch create mode 100644 libqt5-add-support-for-byte-swapping.patch create mode 100644 libqt5-byte-order-byte-is-address0.patch create mode 100644 libqt5-fix-build-failure-xcb.patch create mode 100644 libqt5-fix-regression-in-key-handling.patch create mode 100644 libqt5-improve-keymap-error-handling.patch create mode 100644 libqt5-update-bundled-libxkbcommon-version-to-041.patch diff --git a/libqt5-add-better-support-for-keymap-update-handling.patch b/libqt5-add-better-support-for-keymap-update-handling.patch new file mode 100644 index 0000000..61bb8cc --- /dev/null +++ b/libqt5-add-better-support-for-keymap-update-handling.patch @@ -0,0 +1,666 @@ +From 9c326376c9a27a02ee6abcb897082f538d0002a7 Mon Sep 17 00:00:00 2001 +From: Gatis Paeglis +Date: Thu, 27 Feb 2014 18:05:14 +0100 +Subject: [PATCH] Add better support for keymap update handling + +Use the new X11 support API xkb_x11_* released in libxkbcommon version 0.4.0. + +From the commit message where this API was introduced: + +"These are function to create an xkb_keymap directly from XKB requests +to the X server. This opens up the possibility for X clients to use +xcb + xcb-xkb + xkbcommon as a proper replacement for Xlib + xkbfile for +keyboard support. + +Why not just use the RMLVO that the server puts in the _XKB_RULES_NAMES +property? This does not account for custom keymaps, on-the-fly keymap +modifications, remote clients, etc., so is not a proper solution in +practice. Also, some servers don't even set it. Now, the client just +needs to recreate the keymap in response to a change in the server's +keymap (as Xlib clients do with XRefreshKeyboardMapping() and friends)." + +This patch moves XKEYBOARD presence decision from compile time to runtime +for a proper remote X client support. + +Task-number: QTBUG-31527 +Task-number: QTBUG-32760 +Change-Id: I4d402668cda2126ef180b27022154f96b1874b1d +Reviewed-by: Uli Schlachter +Reviewed-by: Lars Knoll +--- + src/plugins/platforms/xcb/qxcbconnection.cpp | 59 +++---- + src/plugins/platforms/xcb/qxcbconnection.h | 2 + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 218 ++++++++++----------------- + src/plugins/platforms/xcb/qxcbkeyboard.h | 35 +--- + src/plugins/platforms/xcb/xcb-plugin.pro | 8 + 5 files changed, 134 insertions(+), 188 deletions(-) + +--- a/src/plugins/platforms/xcb/qxcbconnection.cpp ++++ b/src/plugins/platforms/xcb/qxcbconnection.cpp +@@ -766,6 +766,7 @@ namespace { + xcb_timestamp_t time; + uint8_t deviceID; + } any; ++ xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; + xcb_xkb_map_notify_event_t map_notify; + xcb_xkb_state_notify_event_t state_notify; + } _xkb_event; +@@ -796,15 +797,11 @@ void QXcbConnection::handleXcbEvent(xcb_ + case XCB_EXPOSE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); + case XCB_BUTTON_PRESS: +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state); +-#endif + handleButtonPress(event); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); + case XCB_BUTTON_RELEASE: +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state); +-#endif + handleButtonRelease(event); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); + case XCB_MOTION_NOTIFY: +@@ -812,9 +809,7 @@ void QXcbConnection::handleXcbEvent(xcb_ + xcb_motion_notify_event_t *mev = (xcb_motion_notify_event_t *)event; + qDebug("xcb: moved mouse to %4d, %4d; button state %X", mev->event_x, mev->event_y, static_cast(m_buttons)); + } +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state); +-#endif + HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + case XCB_CONFIGURE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); +@@ -830,29 +825,21 @@ void QXcbConnection::handleXcbEvent(xcb_ + case XCB_ENTER_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); + case XCB_LEAVE_NOTIFY: +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state); +-#endif + HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); + case XCB_FOCUS_IN: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); + case XCB_FOCUS_OUT: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); + case XCB_KEY_PRESS: +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_key_press_event_t *)event)->state); +-#endif + HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); + case XCB_KEY_RELEASE: +-#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); +-#endif + HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); +-#ifdef QT_NO_XKB + case XCB_MAPPING_NOTIFY: + m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + break; +-#endif + case XCB_SELECTION_REQUEST: + { + xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; +@@ -920,6 +907,8 @@ void QXcbConnection::handleXcbEvent(xcb_ + _xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event); + if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { + switch (xkb_event->any.xkbType) { ++ // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap ++ // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations. + case XCB_XKB_STATE_NOTIFY: + m_keyboard->updateXKBState(&xkb_event->state_notify); + handled = true; +@@ -928,6 +917,12 @@ void QXcbConnection::handleXcbEvent(xcb_ + m_keyboard->handleMappingNotifyEvent(&xkb_event->map_notify); + handled = true; + break; ++ case XCB_XKB_NEW_KEYBOARD_NOTIFY: { ++ xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify; ++ if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) ++ m_keyboard->updateKeymap(); ++ break; ++ } + default: + break; + } +@@ -1661,6 +1656,7 @@ void QXcbConnection::initializeXKB() + #ifndef QT_NO_XKB + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id); + if (!reply || !reply->present) { ++ qWarning() << "Qt: XKEYBOARD extension not present on the X server."; + xkb_first_event = 0; + return; + } +@@ -1670,14 +1666,14 @@ void QXcbConnection::initializeXKB() + xcb_xkb_use_extension_cookie_t xkb_query_cookie; + xcb_xkb_use_extension_reply_t *xkb_query; + +- xkb_query_cookie = xcb_xkb_use_extension(c, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); ++ xkb_query_cookie = xcb_xkb_use_extension(c, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION); + xkb_query = xcb_xkb_use_extension_reply(c, xkb_query_cookie, 0); + + if (!xkb_query) { + qWarning("Qt: Failed to initialize XKB extension"); + return; + } else if (!xkb_query->supported) { +- qWarning("Qt: Unsupported XKB version (want %d %d, has %d %d)", ++ qWarning("Qt: Unsupported XKB version (We want %d %d, but X server has %d %d)", + XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION, + xkb_query->serverMajor, xkb_query->serverMinor); + free(xkb_query); +@@ -1687,25 +1683,28 @@ void QXcbConnection::initializeXKB() + has_xkb = true; + free(xkb_query); + +- uint affectMap, map; +- affectMap = map = 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_KEY_BEHAVIORS | +- XCB_XKB_MAP_PART_VIRTUAL_MODS | +- XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP; ++ const uint16_t required_map_parts = (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_KEY_BEHAVIORS | ++ XCB_XKB_MAP_PART_VIRTUAL_MODS | ++ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP); ++ ++ const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | ++ XCB_XKB_EVENT_TYPE_MAP_NOTIFY | ++ XCB_XKB_EVENT_TYPE_STATE_NOTIFY); + +- // Xkb events are reported to all interested clients without regard ++ // XKB events are reported to all interested clients without regard + // to the current keyboard input focus or grab state + xcb_void_cookie_t select = xcb_xkb_select_events_checked(c, + XCB_XKB_ID_USE_CORE_KBD, +- XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY, ++ required_events, + 0, +- XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY, +- affectMap, +- map, ++ required_events, ++ required_map_parts, ++ required_map_parts, + 0); + + xcb_generic_error_t *error = xcb_request_check(c, select); +--- a/src/plugins/platforms/xcb/qxcbconnection.h ++++ b/src/plugins/platforms/xcb/qxcbconnection.h +@@ -54,7 +54,7 @@ + #include + + // This is needed to make Qt compile together with XKB. xkb.h is using a variable +-// which is called 'explicit', this is a reserved keyword in c++ */ ++// which is called 'explicit', this is a reserved keyword in c++ + #ifndef QT_NO_XKB + #define explicit dont_use_cxx_explicit + #include +--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp +@@ -658,6 +658,7 @@ void QXcbKeyboard::clearXKBConfig() + void QXcbKeyboard::updateKeymap() + { + m_config = true; ++ // set xkb context object + if (!xkb_context) { + xkb_context = xkb_context_new((xkb_context_flags)0); + if (!xkb_context) { +@@ -666,67 +667,50 @@ void QXcbKeyboard::updateKeymap() + return; + } + } +- readXKBConfig(); +- // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names +- if (xkb_keymap) +- xkb_keymap_unref(xkb_keymap); ++ // update xkb keymap object ++ xkb_keymap_unref(xkb_keymap); ++ xkb_keymap = 0; + +- xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0); ++ struct xkb_state *new_state = 0; ++#ifndef QT_NO_XKB ++ if (connection()->hasXKB()) { ++ xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, xcb_connection(), core_device_id, (xkb_keymap_compile_flags)0); ++ if (xkb_keymap) { ++ // Create a new keyboard state object for a keymap ++ new_state = xkb_x11_state_new_from_device(xkb_keymap, xcb_connection(), core_device_id); ++ } ++ } ++#endif ++ if (!xkb_keymap) { ++ // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names ++ readXKBConfig(); ++ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0); ++ if (xkb_keymap) ++ new_state = xkb_state_new(xkb_keymap); ++ } + + if (!xkb_keymap) { + qWarning("Qt: Failed to compile a keymap"); + m_config = false; +- return; + } +- // Create a new keyboard state object for a keymap +- struct xkb_state *new_state = xkb_state_new(xkb_keymap); + if (!new_state) { +- qWarning("Qt: Failed to create a new keyboard state"); ++ qWarning("Qt: Failed to create xkb state"); + m_config = false; +- return; + } ++ if (!m_config) ++ return; + +- if (xkb_state) { +- xkb_state_unref(xkb_state); +- xkb_state = new_state; +- } else { +- xkb_state = new_state; +-#ifndef QT_NO_XKB +- // get initial state from the X server (and keep it up-to-date at all times) +- xcb_xkb_get_state_cookie_t state; +- xcb_xkb_get_state_reply_t *init_state; +- +- xcb_connection_t *c = xcb_connection(); +- state = xcb_xkb_get_state(c, XCB_XKB_ID_USE_CORE_KBD); +- init_state = xcb_xkb_get_state_reply(c, state, 0); +- if (!init_state) { +- qWarning("Qt: couldn't retrieve an initial keyboard state"); +- return; +- } +- /* The xkb keyboard state is comprised of the state of all keyboard modifiers, +- the keyboard group, and the state of the pointer buttons */ +- xkb_state_update_mask(xkb_state, +- init_state->baseMods, +- init_state->latchedMods, +- init_state->lockedMods, +- init_state->baseGroup, +- init_state->latchedGroup, +- init_state->lockedGroup); +- free(init_state); +-#else ++ // update xkb state object ++ xkb_state_unref(xkb_state); ++ xkb_state = new_state; ++ if (!connection()->hasXKB()) + updateXKBMods(); +-#endif +- } + } + + #ifndef QT_NO_XKB + void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) + { +- if (!m_config) +- return; +- +- if (connection()->hasXKB()) { +- ++ if (m_config && connection()->hasXKB()) { + const xkb_state_component newState + = xkb_state_update_mask(xkb_state, + state->baseMods, +@@ -741,35 +725,34 @@ void QXcbKeyboard::updateXKBState(xcb_xk + } + } + } ++#endif + +-#else + void QXcbKeyboard::updateXKBStateFromCore(quint16 state) + { +- if (!m_config) +- return; ++ if (m_config && !connection()->hasXKB()) { ++ const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); ++ const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); ++ const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); ++ const quint32 xkbMask = xkbModMask(state); ++ ++ const quint32 latched = modsLatched & xkbMask; ++ const quint32 locked = modsLocked & xkbMask; ++ quint32 depressed = modsDepressed & xkbMask; ++ // set modifiers in depressed if they don't appear in any of the final masks ++ depressed |= ~(depressed | latched | locked) & xkbMask; + +- const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); +- const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); +- const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); +- const quint32 xkbMask = xkbModMask(state); +- +- const quint32 latched = modsLatched & xkbMask; +- const quint32 locked = modsLocked & xkbMask; +- quint32 depressed = modsDepressed & xkbMask; +- // set modifiers in depressed if they don't appear in any of the final masks +- depressed |= ~(depressed | latched | locked) & xkbMask; +- +- const xkb_state_component newState +- = xkb_state_update_mask(xkb_state, +- depressed, +- latched, +- locked, +- 0, +- 0, +- (state >> 13) & 3); // bits 13 and 14 report the state keyboard group ++ const xkb_state_component newState ++ = xkb_state_update_mask(xkb_state, ++ depressed, ++ latched, ++ locked, ++ 0, ++ 0, ++ (state >> 13) & 3); // bits 13 and 14 report the state keyboard group + +- if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) { +- //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)"); ++ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) { ++ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)"); ++ } + } + } + +@@ -799,16 +782,15 @@ quint32 QXcbKeyboard::xkbModMask(quint16 + + void QXcbKeyboard::updateXKBMods() + { +- xkb_mods.shift = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT); +- xkb_mods.lock = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS); +- xkb_mods.control = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL); +- xkb_mods.mod1 = xkb_map_mod_get_index(xkb_keymap, "Mod1"); +- xkb_mods.mod2 = xkb_map_mod_get_index(xkb_keymap, "Mod2"); +- xkb_mods.mod3 = xkb_map_mod_get_index(xkb_keymap, "Mod3"); +- xkb_mods.mod4 = xkb_map_mod_get_index(xkb_keymap, "Mod4"); +- xkb_mods.mod5 = xkb_map_mod_get_index(xkb_keymap, "Mod5"); ++ xkb_mods.shift = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT); ++ xkb_mods.lock = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS); ++ xkb_mods.control = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL); ++ xkb_mods.mod1 = xkb_keymap_mod_get_index(xkb_keymap, "Mod1"); ++ xkb_mods.mod2 = xkb_keymap_mod_get_index(xkb_keymap, "Mod2"); ++ xkb_mods.mod3 = xkb_keymap_mod_get_index(xkb_keymap, "Mod3"); ++ xkb_mods.mod4 = xkb_keymap_mod_get_index(xkb_keymap, "Mod4"); ++ xkb_mods.mod5 = xkb_keymap_mod_get_index(xkb_keymap, "Mod5"); + } +-#endif + + QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const + { +@@ -893,10 +875,8 @@ QList QXcbKeyboard::possibleKeys(co + result += (qtKey + mods); + } + } +- if (kb_state) +- xkb_state_unref(kb_state); +- if (fallback_keymap) +- xkb_keymap_unref(fallback_keymap); ++ xkb_state_unref(kb_state); ++ xkb_keymap_unref(fallback_keymap); + + return result; + } +@@ -963,58 +943,41 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnectio + , xkb_context(0) + , xkb_keymap(0) + , xkb_state(0) +-#ifndef QT_NO_XKB + , core_device_id(0) +-#endif + { + memset(&xkb_names, 0, sizeof(xkb_names)); +- updateKeymap(); + #ifndef QT_NO_XKB + if (connection->hasXKB()) { +- + updateVModMapping(); + updateVModToRModMapping(); +- +- // get the core keyboard id +- xcb_xkb_get_device_info_cookie_t device_id_cookie; +- xcb_xkb_get_device_info_reply_t *device_id; +- +- device_id_cookie = xcb_xkb_get_device_info(xcb_connection(), +- XCB_XKB_ID_USE_CORE_KBD, +- 0, 0, 0, 0, 0, 0); +- +- device_id = xcb_xkb_get_device_info_reply(xcb_connection(), device_id_cookie, 0); +- if (!device_id) { ++ core_device_id = xkb_x11_get_core_keyboard_device_id(xcb_connection()); ++ if (core_device_id == -1) { + qWarning("Qt: couldn't get core keyboard device info"); + return; + } +- +- core_device_id = device_id->deviceID; +- free(device_id); ++ } else { ++#endif ++ m_key_symbols = xcb_key_symbols_alloc(xcb_connection()); ++ updateModifiers(); ++#ifndef QT_NO_XKB + } +-#else +- m_key_symbols = xcb_key_symbols_alloc(xcb_connection()); +- updateModifiers(); + #endif ++ updateKeymap(); + } + + QXcbKeyboard::~QXcbKeyboard() + { +- if (xkb_state) +- xkb_state_unref(xkb_state); +- if (xkb_keymap) +- xkb_keymap_unref(xkb_keymap); +- if (xkb_context) +- xkb_context_unref(xkb_context); +-#ifdef QT_NO_XKB +- xcb_key_symbols_free(m_key_symbols); +-#endif ++ xkb_state_unref(xkb_state); ++ xkb_keymap_unref(xkb_keymap); ++ xkb_context_unref(xkb_context); ++ if (!connection()->hasXKB()) ++ xcb_key_symbols_free(m_key_symbols); + clearXKBConfig(); + } + +-#ifndef QT_NO_XKB + void QXcbKeyboard::updateVModMapping() + { ++#ifndef QT_NO_XKB + xcb_xkb_get_names_cookie_t names_cookie; + xcb_xkb_get_names_reply_t *name_reply; + xcb_xkb_get_names_value_list_t names_list; +@@ -1078,10 +1041,12 @@ void QXcbKeyboard::updateVModMapping() + } + + free(name_reply); ++#endif + } + + void QXcbKeyboard::updateVModToRModMapping() + { ++#ifndef QT_NO_XKB + xcb_xkb_get_map_cookie_t map_cookie; + xcb_xkb_get_map_reply_t *map_reply; + xcb_xkb_get_map_map_t map; +@@ -1144,8 +1109,9 @@ void QXcbKeyboard::updateVModToRModMappi + + free(map_reply); + resolveMaskConflicts(); ++#endif + } +-#else ++ + void QXcbKeyboard::updateModifiers() + { + // The core protocol does not provide a convenient way to determine the mapping +@@ -1209,7 +1175,6 @@ void QXcbKeyboard::updateModifiers() + free(modMapReply); + resolveMaskConflicts(); + } +-#endif + + void QXcbKeyboard::resolveMaskConflicts() + { +@@ -1292,17 +1257,9 @@ void QXcbKeyboard::handleKeyEvent(QWindo + + if (!m_config) + return; +- // It is crucial the order of xkb_state_key_get_one_sym & +- // xkb_state_update_key operations is not reversed! ++ ++ // It is crucial the order of xkb_state_key_get_one_sym & xkb_state_update_key operations is not reversed! + xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code); +-#ifdef QT_NO_XKB +- enum xkb_key_direction direction; +- if (type == QEvent::KeyPress) +- direction = XKB_KEY_DOWN; +- else +- direction = XKB_KEY_UP; +- xkb_state_update_key(xkb_state, code, direction); +-#endif + + QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); + QMetaMethod method; +@@ -1422,17 +1379,14 @@ void QXcbKeyboard::handleKeyReleaseEvent + void QXcbKeyboard::handleMappingNotifyEvent(const void *event) + { + updateKeymap(); +-#ifdef QT_NO_XKB +- void *ev = const_cast(event); +- xcb_refresh_keyboard_mapping(m_key_symbols, static_cast(ev)); +- updateModifiers(); +-#else +- Q_UNUSED(event) + if (connection()->hasXKB()) { + updateVModMapping(); + updateVModToRModMapping(); ++ } else { ++ void *ev = const_cast(event); ++ xcb_refresh_keyboard_mapping(m_key_symbols, static_cast(ev)); ++ updateModifiers(); + } +-#endif + } + + QT_END_NAMESPACE +--- a/src/plugins/platforms/xcb/qxcbkeyboard.h ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.h +@@ -44,11 +44,15 @@ + + #include "qxcbobject.h" + +-#ifdef QT_NO_XKB + #include +-#endif + + #include ++#ifndef QT_NO_XKB ++// note: extern won't be needed from libxkbcommon 0.4.1 and above ++extern "C" { ++#include ++} ++#endif + + #include + +@@ -65,41 +69,37 @@ public: + + void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event); + void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event); +- + void handleMappingNotifyEvent(const void *event); + + Qt::KeyboardModifiers translateModifiers(int s) const; +- + void updateKeymap(); + QList possibleKeys(const QKeyEvent *e) const; + +-#ifdef QT_NO_XKB +- void updateXKBStateFromCore(quint16 state); ++ // when XKEYBOARD not present on the X server + void updateXKBMods(); + quint32 xkbModMask(quint16 state); +-#else +- int coreDeviceId() { return core_device_id; } ++ void updateXKBStateFromCore(quint16 state); ++ // when XKEYBOARD is present on the X server ++ int coreDeviceId() const { return core_device_id; } ++#ifndef QT_NO_XKB + void updateXKBState(xcb_xkb_state_notify_event_t *state); + #endif + + protected: + void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); +- void resolveMaskConflicts(); + ++ void resolveMaskConflicts(); + QString keysymToUnicode(xcb_keysym_t sym) const; +- + int keysymToQtKey(xcb_keysym_t keysym) const; + int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; + + void readXKBConfig(); + void clearXKBConfig(); +- +-#ifdef QT_NO_XKB ++ // when XKEYBOARD not present on the X server + void updateModifiers(); +-#else ++ // when XKEYBOARD is present on the X server + void updateVModMapping(); + void updateVModToRModMapping(); +-#endif + + private: + bool m_config; +@@ -120,9 +120,8 @@ private: + + _mod_masks rmod_masks; + +-#ifdef QT_NO_XKB ++ // when XKEYBOARD not present on the X server + xcb_key_symbols_t *m_key_symbols; +- + struct _xkb_mods { + xkb_mod_index_t shift; + xkb_mod_index_t lock; +@@ -133,12 +132,10 @@ private: + xkb_mod_index_t mod4; + xkb_mod_index_t mod5; + }; +- + _xkb_mods xkb_mods; +-#else ++ // when XKEYBOARD is present on the X server + _mod_masks vmod_masks; + int core_device_id; +-#endif + }; + + QT_END_NAMESPACE +--- a/src/plugins/platforms/xcb/xcb-plugin.pro ++++ b/src/plugins/platforms/xcb/xcb-plugin.pro +@@ -121,12 +121,8 @@ contains(QT_CONFIG, xcb-qt) { + INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude + LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static + } else { +- LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape +- contains(DEFINES, QT_NO_XKB) { +- LIBS += -lxcb-keysyms +- } else { +- LIBS += -lxcb-xkb +- } ++ LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms ++ !contains(DEFINES, QT_NO_XKB):LIBS += -lxcb-xkb + } + + # libxkbcommon diff --git a/libqt5-add-support-for-byte-swapping.patch b/libqt5-add-support-for-byte-swapping.patch new file mode 100644 index 0000000..0920243 --- /dev/null +++ b/libqt5-add-support-for-byte-swapping.patch @@ -0,0 +1,122 @@ +From a3ed9b781cb0e1fa4ae3b1cedcd63bd394903db7 Mon Sep 17 00:00:00 2001 +From: Egbert Eich +Date: Tue, 18 Mar 2014 18:29:02 +0100 +Subject: [PATCH] [xcb/xsettings] Add support for byte swapping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The XSettings protocol is not endian neutral. Instead it holds +information about endianness in the first byte. It uses the same +convention as X11/X.h does. +So far byte order handling was missing leading to nasty crashes +when byte order between clients setting and reading XSettings +differed. This patch fixes this. +Using the X11/X.h conventions seems to be an 'established standard', +this piece is missing from the Xsettings specifications. Therefore +this fix may introduce spurious regressions as other Xsettings +'providers' may use a different convention. To detect this and +to avoid crashes the fix also adds checks to avoid reading past +the end of the of the Xsettings data blob. If problems are +encountered: warn and bail. + +Change-Id: If8acb23cca2478369633129af2d99e122a84cede +Reviewed-by: Jørgen Lind +--- + src/plugins/platforms/xcb/qxcbxsettings.cpp | 43 +++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 11 deletions(-) + +diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp +index 141a6cc..26d95e9 100644 +--- a/src/plugins/platforms/xcb/qxcbxsettings.cpp ++++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp +@@ -42,6 +42,7 @@ + #include "qxcbxsettings.h" + + #include ++#include + + #include + +@@ -149,47 +150,67 @@ public: + { + if (xSettings.length() < 12) + return; +- // we ignore byteorder for now + char byteOrder = xSettings.at(1); +- Q_UNUSED(byteOrder); +- uint number_of_settings = *reinterpret_cast(xSettings.mid(8,4).constData()); ++ if (byteOrder != LSBFirst && byteOrder != MSBFirst) { ++ qWarning("%s ByteOrder byte %d not 0 or 1", Q_FUNC_INFO , byteOrder); ++ return; ++ } ++ ++#define ADJUST_BO(b, t, x) \ ++ ((b == LSBFirst) ? \ ++ qFromLittleEndian((const uchar *)(x)) : \ ++ qFromBigEndian((const uchar *)(x))) ++#define VALIDATE_LENGTH(x) \ ++ if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) { \ ++ qWarning("%s Length %d runs past end of data", Q_FUNC_INFO , x); \ ++ return; \ ++ } + ++ uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData()); + const char *data = xSettings.constData() + 12; + size_t offset = 0; + for (uint i = 0; i < number_of_settings; i++) { + int local_offset = 0; ++ VALIDATE_LENGTH(2); + XSettingsType type = static_cast(*reinterpret_cast(data + offset)); + local_offset += 2; + +- quint16 name_len = *reinterpret_cast(data + offset + local_offset); ++ VALIDATE_LENGTH(2); ++ quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); + local_offset += 2; + ++ VALIDATE_LENGTH(name_len); + QByteArray name(data + offset + local_offset, name_len); + local_offset += round_to_nearest_multiple_of_4(name_len); + +- int last_change_serial = *reinterpret_cast(data + offset + local_offset); ++ VALIDATE_LENGTH(4); ++ int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); + Q_UNUSED(last_change_serial); + local_offset += 4; + + QVariant value; + if (type == XSettingsTypeString) { +- int value_length = *reinterpret_cast(data + offset + local_offset); ++ VALIDATE_LENGTH(4); ++ int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); + local_offset+=4; ++ VALIDATE_LENGTH(value_length); + QByteArray value_string(data + offset + local_offset, value_length); + value.setValue(value_string); + local_offset += round_to_nearest_multiple_of_4(value_length); + } else if (type == XSettingsTypeInteger) { +- int value_length = *reinterpret_cast(data + offset + local_offset); ++ VALIDATE_LENGTH(4); ++ int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); + local_offset += 4; + value.setValue(value_length); + } else if (type == XSettingsTypeColor) { +- quint16 red = *reinterpret_cast(data + offset + local_offset); ++ VALIDATE_LENGTH(2*4); ++ quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); + local_offset += 2; +- quint16 green = *reinterpret_cast(data + offset + local_offset); ++ quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); + local_offset += 2; +- quint16 blue = *reinterpret_cast(data + offset + local_offset); ++ quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); + local_offset += 2; +- quint16 alpha= *reinterpret_cast(data + offset + local_offset); ++ quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset); + local_offset += 2; + QColor color_value(red,green,blue,alpha); + value.setValue(color_value); +-- +1.8.4.5 + diff --git a/libqt5-byte-order-byte-is-address0.patch b/libqt5-byte-order-byte-is-address0.patch new file mode 100644 index 0000000..94810e9 --- /dev/null +++ b/libqt5-byte-order-byte-is-address0.patch @@ -0,0 +1,35 @@ +From 5819ffe492cf3cd98718819b1bd837819318d82e Mon Sep 17 00:00:00 2001 +From: Egbert Eich +Date: Sun, 6 Apr 2014 16:54:03 +0200 +Subject: [PATCH] [xcb/xsettings] Byte order byte is at address 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Accoring to + http://standards.freedesktop.org\ + /xsettings-spec/xsettings-spec-0.5.html +the byte order byte is address 0 (not 1). + +Change-Id: I441084a7f24908dd8a504648bfc50ba2d486a586 +Reviewed-by: Jørgen Lind +--- + src/plugins/platforms/xcb/qxcbxsettings.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp +index 26d95e9..17b40a4 100644 +--- a/src/plugins/platforms/xcb/qxcbxsettings.cpp ++++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp +@@ -150,7 +150,7 @@ public: + { + if (xSettings.length() < 12) + return; +- char byteOrder = xSettings.at(1); ++ char byteOrder = xSettings.at(0); + if (byteOrder != LSBFirst && byteOrder != MSBFirst) { + qWarning("%s ByteOrder byte %d not 0 or 1", Q_FUNC_INFO , byteOrder); + return; +-- +1.8.4.5 + diff --git a/libqt5-fix-build-failure-xcb.patch b/libqt5-fix-build-failure-xcb.patch new file mode 100644 index 0000000..c4c8017 --- /dev/null +++ b/libqt5-fix-build-failure-xcb.patch @@ -0,0 +1,92 @@ +From ee3dea8d3fdc9477f3a54e5457e19be1d0c61de9 Mon Sep 17 00:00:00 2001 +From: Gatis Paeglis +Date: Mon, 31 Mar 2014 14:48:29 +0200 +Subject: [PATCH] [xcb] Fix build failure + +Build failure was introduced by 9bb634a6176c639bd6b52d58151e9927c30919d0. + +When linking with systems provided libxkbcommon, then DFLT_XKB_CONFIG_ROOT +can't be accessed directly. + +The reason that this slip through CI is that on CI machines Qt +is build with bundled version of libxkbcommon. + +In addition this patch improves keymap error message, by making it more explicit for +users what could be the reasons for "keymap compilation" failures and what should +be done to make input work. As it turns out this is a common issue on old systems, +servers and some VNC clients. + +Task-number: QTBUG-37971 + +Change-Id: I77667a404150ee7ab8465a065e23ca5eea63c33b +Reviewed-by: Uli Schlachter +Reviewed-by: Thiago Macieira +Reviewed-by: Lars Knoll +--- + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 28 +++++++++------------------- + src/plugins/platforms/xcb/qxcbkeyboard.h | 2 +- + 2 files changed, 10 insertions(+), 20 deletions(-) + +--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp +@@ -663,23 +663,14 @@ void QXcbKeyboard::clearXKBConfig() + memset(&xkb_names, 0, sizeof(xkb_names)); + } + +-void QXcbKeyboard::printKeymapError(const QString &error) const ++void QXcbKeyboard::printKeymapError(const char *error) const + { +- qWarning() << "Qt: " << error; +- // check if XKB config root is a valid path +- const QDir xkbRoot = qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT") +- ? QString::fromLocal8Bit(qgetenv("QT_XKB_CONFIG_ROOT")) +- : DFLT_XKB_CONFIG_ROOT; +- if (!xkbRoot.exists() || xkbRoot.dirName() != "xkb") { +- qWarning() << "Set QT_XKB_CONFIG_ROOT to provide a valid XKB configuration data path, current search paths: " +- << xkbRoot.path() << ". Use ':' as separator to provide several search paths."; +- return; +- } +- qWarning() << "_XKB_RULES_NAMES property contains:" << "\nrules : " << xkb_names.rules << +- "\nmodel : " << xkb_names.model << "\nlayout : " << xkb_names.layout << +- "\nvariant : " << xkb_names.variant << "\noptions : " << xkb_names.options << +- "\nIf this looks like a valid keyboard layout information then you might need to " +- "update XKB configuration data on the system (http://cgit.freedesktop.org/xkeyboard-config/)."; ++ qWarning() << error << "Current XKB configuration data search paths are: "; ++ for (unsigned int i = 0; i < xkb_context_num_include_paths(xkb_context); ++i) ++ qWarning() << xkb_context_include_path_get(xkb_context, i); ++ qWarning() << "Use QT_XKB_CONFIG_ROOT environmental variable to provide an additional search path, " ++ "add ':' as separator to provide several search paths and/or make sure that XKB configuration data " ++ "directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ ."; + } + + void QXcbKeyboard::updateKeymap() +@@ -696,7 +687,7 @@ void QXcbKeyboard::updateKeymap() + xkb_context = xkb_context_new((xkb_context_flags)0); + } + if (!xkb_context) { +- printKeymapError("Failed to create XKB context!"); ++ printKeymapError("Qt: Failed to create XKB context!"); + m_config = false; + return; + } +@@ -731,8 +722,7 @@ void QXcbKeyboard::updateKeymap() + if (xkb_keymap) { + new_state = xkb_state_new(xkb_keymap); + } else { +- // failed to compile from RMLVO, give a verbose error message +- printKeymapError("Qt: Failed to compile a keymap!"); ++ printKeymapError("Failed to compile a keymap!"); + m_config = false; + return; + } +--- a/src/plugins/platforms/xcb/qxcbkeyboard.h ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.h +@@ -92,7 +92,7 @@ protected: + QString keysymToUnicode(xcb_keysym_t sym) const; + int keysymToQtKey(xcb_keysym_t keysym) const; + int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; +- void printKeymapError(const QString &error) const; ++ void printKeymapError(const char *error) const; + + void readXKBConfig(); + void clearXKBConfig(); diff --git a/libqt5-fix-regression-in-key-handling.patch b/libqt5-fix-regression-in-key-handling.patch new file mode 100644 index 0000000..888f0be --- /dev/null +++ b/libqt5-fix-regression-in-key-handling.patch @@ -0,0 +1,86 @@ +From 6ad458bc93162753e448eea28499e778e2946d2c Mon Sep 17 00:00:00 2001 +From: Gatis Paeglis +Date: Mon, 31 Mar 2014 17:13:20 +0200 +Subject: [PATCH] Fix regression in key handling. + +libxkbcommon 0.4.1 added two new functions, xkb_state_key_get_utf{8,32}(). They +combine the operations of xkb_state_key_get_syms() and xkb_keysym_to_utf{8,32}(). + +The xkb_state_key_get_utf{8,32}() functions now apply Control transformation: when +the Control modifier is active, the string is converted to an appropriate control +character. This matches the behavior of libX11's XLookupString(3), and is required by +the XKB specification: + +http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier + +Task-number: QTBUG-36281 +Change-Id: Ib45f45d801291c171640600384107a35d7d56b9b +Reviewed-by: Ran Benita +Reviewed-by: Lars Knoll +--- + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 19 ++++++++----------- + src/plugins/platforms/xcb/qxcbkeyboard.h | 2 +- + 2 files changed, 9 insertions(+), 12 deletions(-) + +--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp +@@ -853,7 +853,7 @@ QList QXcbKeyboard::possibleKeys(co + return QList(); + + QList result; +- int baseQtKey = keysymToQtKey(sym, modifiers, keysymToUnicode(sym)); ++ int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, event->nativeScanCode())); + result += (baseQtKey + modifiers); // The base key is _always_ valid, of course + + xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); +@@ -900,7 +900,7 @@ QList QXcbKeyboard::possibleKeys(co + continue; + + Qt::KeyboardModifiers mods = modifiers & ~neededMods; +- qtKey = keysymToQtKey(sym, mods, keysymToUnicode(sym)); ++ qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, event->nativeScanCode())); + + if (qtKey == baseQtKey) + continue; +@@ -1316,7 +1316,8 @@ void QXcbKeyboard::handleKeyEvent(QWindo + } + + Qt::KeyboardModifiers modifiers = translateModifiers(state); +- QString string = keysymToUnicode(sym); ++ ++ QString string = lookupString(xkb_state, code); + int count = string.size(); + string.truncate(count); + +@@ -1379,16 +1380,12 @@ void QXcbKeyboard::handleKeyEvent(QWindo + } + } + +-QString QXcbKeyboard::keysymToUnicode(xcb_keysym_t sym) const ++QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const + { + QByteArray chars; +- int bytes; +- chars.resize(7); +- bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); +- if (bytes == -1) +- qWarning("QXcbKeyboard::handleKeyEvent - buffer too small"); +- chars.resize(bytes-1); +- ++ chars.resize(1 + xkb_state_key_get_utf8(state, code, 0, 0)); ++ // equivalent of XLookupString ++ xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); + return QString::fromUtf8(chars); + } + +--- a/src/plugins/platforms/xcb/qxcbkeyboard.h ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.h +@@ -86,7 +86,7 @@ protected: + void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); + + void resolveMaskConflicts(); +- QString keysymToUnicode(xcb_keysym_t sym) const; ++ QString lookupString(struct xkb_state *state, xcb_keycode_t code) const; + int keysymToQtKey(xcb_keysym_t keysym) const; + int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; + void printKeymapError(const char *error) const; diff --git a/libqt5-improve-keymap-error-handling.patch b/libqt5-improve-keymap-error-handling.patch new file mode 100644 index 0000000..c9e9c0e --- /dev/null +++ b/libqt5-improve-keymap-error-handling.patch @@ -0,0 +1,158 @@ +From 9bb634a6176c639bd6b52d58151e9927c30919d0 Mon Sep 17 00:00:00 2001 +From: Gatis Paeglis +Date: Mon, 3 Mar 2014 18:00:33 +0100 +Subject: [PATCH] Improve keymap error handling + +- add QT_XKB_CONFIG_ROOT envvar, this can be used to provide an alternative + XKB configuration search paths (default XKB configuration root is detected when + building Qt library). At runtime these paths might change - when dropping Qt + application binary into a system with different setup. + +Change-Id: Ia21a3e7f0339c95793c1f543d1a95b1591e5d8df +Reviewed-by: Uli Schlachter +Reviewed-by: Lars Knoll +--- + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 77 ++++++++++++++++++++++------- + src/plugins/platforms/xcb/qxcbkeyboard.h | 1 + 2 files changed, 61 insertions(+), 17 deletions(-) + +--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp +@@ -38,20 +38,22 @@ + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +- + #include "qxcbkeyboard.h" + #include "qxcbwindow.h" + #include "qxcbscreen.h" +-#include ++ + #include ++#include ++#include ++#include ++ + #include + #include ++#include + #include +-#include + +-#include +-#include +-#include ++#include ++#include + + #ifndef XK_ISO_Left_Tab + #define XK_ISO_Left_Tab 0xFE20 +@@ -619,6 +621,12 @@ void QXcbKeyboard::readXKBConfig() + char *xkb_config = (char *)xcb_get_property_value(config_reply); + int length = xcb_get_property_value_length(config_reply); + ++ // on old X servers xkb_config can be 0 even if config_reply indicates a succesfull read ++ if (!xkb_config || length == 0) ++ return; ++ // ### TODO some X servers don't set _XKB_RULES_NAMES at all, in these cases it is filled ++ // with gibberish, we would need to do some kind of sanity check ++ + char *names[5] = { 0, 0, 0, 0, 0 }; + char *p = xkb_config, *end = p + length; + int i = 0; +@@ -655,17 +663,45 @@ void QXcbKeyboard::clearXKBConfig() + memset(&xkb_names, 0, sizeof(xkb_names)); + } + ++void QXcbKeyboard::printKeymapError(const QString &error) const ++{ ++ qWarning() << "Qt: " << error; ++ // check if XKB config root is a valid path ++ const QDir xkbRoot = qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT") ++ ? QString::fromLocal8Bit(qgetenv("QT_XKB_CONFIG_ROOT")) ++ : DFLT_XKB_CONFIG_ROOT; ++ if (!xkbRoot.exists() || xkbRoot.dirName() != "xkb") { ++ qWarning() << "Set QT_XKB_CONFIG_ROOT to provide a valid XKB configuration data path, current search paths: " ++ << xkbRoot.path() << ". Use ':' as separator to provide several search paths."; ++ return; ++ } ++ qWarning() << "_XKB_RULES_NAMES property contains:" << "\nrules : " << xkb_names.rules << ++ "\nmodel : " << xkb_names.model << "\nlayout : " << xkb_names.layout << ++ "\nvariant : " << xkb_names.variant << "\noptions : " << xkb_names.options << ++ "\nIf this looks like a valid keyboard layout information then you might need to " ++ "update XKB configuration data on the system (http://cgit.freedesktop.org/xkeyboard-config/)."; ++} ++ + void QXcbKeyboard::updateKeymap() + { + m_config = true; + // set xkb context object + if (!xkb_context) { +- xkb_context = xkb_context_new((xkb_context_flags)0); ++ if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) { ++ xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES); ++ QList xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':'); ++ foreach (QByteArray xkbRoot, xkbRootList) ++ xkb_context_include_path_append(xkb_context, xkbRoot.constData()); ++ } else { ++ xkb_context = xkb_context_new((xkb_context_flags)0); ++ } + if (!xkb_context) { +- qWarning("Qt: Failed to create XKB context"); ++ printKeymapError("Failed to create XKB context!"); + m_config = false; + return; + } ++ // log only critical errors, we do our own error logging from printKeymapError() ++ xkb_context_set_log_level(xkb_context, (xkb_log_level)XKB_LOG_LEVEL_CRITICAL); + } + // update xkb keymap object + xkb_keymap_unref(xkb_keymap); +@@ -685,21 +721,28 @@ void QXcbKeyboard::updateKeymap() + // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names + readXKBConfig(); + xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0); +- if (xkb_keymap) ++ if (!xkb_keymap) { ++ // last fallback is to used hard-coded keymap name, see DEFAULT_XKB_* in xkbcommon.pri ++ qWarning() << "Qt: Could not determine keyboard configuration data" ++ " from X server, will use hard-coded keymap configuration."; ++ clearXKBConfig(); ++ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0); ++ } ++ if (xkb_keymap) { + new_state = xkb_state_new(xkb_keymap); +- } ++ } else { ++ // failed to compile from RMLVO, give a verbose error message ++ printKeymapError("Qt: Failed to compile a keymap!"); ++ m_config = false; ++ return; ++ } + +- if (!xkb_keymap) { +- qWarning("Qt: Failed to compile a keymap"); +- m_config = false; + } + if (!new_state) { +- qWarning("Qt: Failed to create xkb state"); ++ qWarning("Qt: Failed to create xkb state!"); + m_config = false; +- } +- if (!m_config) + return; +- ++ } + // update xkb state object + xkb_state_unref(xkb_state); + xkb_state = new_state; +--- a/src/plugins/platforms/xcb/qxcbkeyboard.h ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.h +@@ -92,6 +92,7 @@ protected: + QString keysymToUnicode(xcb_keysym_t sym) const; + int keysymToQtKey(xcb_keysym_t keysym) const; + int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; ++ void printKeymapError(const QString &error) const; + + void readXKBConfig(); + void clearXKBConfig(); diff --git a/libqt5-qtbase.changes b/libqt5-qtbase.changes index e6bd80d..0045100 100644 --- a/libqt5-qtbase.changes +++ b/libqt5-qtbase.changes @@ -1,3 +1,22 @@ +------------------------------------------------------------------- +Tue Apr 8 06:56:21 UTC 2014 - mlin@suse.com + +- Add support for byte swapping, bnc#866709 + * Add libqt5-add-support-for-byte-swapping.patch + * Add libqt5-byte-order-byte-is-address0.patch +- Fix keyboard remapping not applied on Qt5, bnc#866051 + * Add backported libqt5-add-better-support-for-keymap-update-handling.patch + * Add backported libqt5-improve-keymap-error-handling.patch + * Add backported libqt5-fix-build-failure-xcb.patch + * Add backported libqt5-update-bundled-libxkbcommon-version-to-041.patch + * Add backported libqt5-fix-regression-in-key-handling.patch + +------------------------------------------------------------------- +Fri Mar 28 08:22:53 UTC 2014 - hrvoje.senjan@gmail.com + +- The no-neon switch no longer exists with 5.3, so drop it: fixes + build on arm/aarch64 + ------------------------------------------------------------------- Tue Mar 25 11:44:16 UTC 2014 - hrvoje.senjan@gmail.com diff --git a/libqt5-qtbase.spec b/libqt5-qtbase.spec index 4ab4db3..e80adff 100644 --- a/libqt5-qtbase.spec +++ b/libqt5-qtbase.spec @@ -46,6 +46,20 @@ Patch131: qmake-add-usr-include.diff Patch132: use-freetype-default.patch # PATCH-FIX-UPSTREAM f1ee10f81ac18789e9a7dc715b464415ba2bc2b8.patch -- prefer QPA implementation in qsystemtrayicon_x11 if available Patch133: f1ee10f81ac18789e9a7dc715b464415ba2bc2b8.patch +# PATCH-FIX-UPSTREAM libqt5-add-better-support-for-keymap-update-handling.patch -- fixed keyboard remapping not applied(bnc#866051, qtbug#31527) +Patch134: libqt5-add-better-support-for-keymap-update-handling.patch +# PATCH-FIX-UPSTREAM libqt5-improve-keymap-error-handling.patch -- improve keymap error handling +Patch135: libqt5-improve-keymap-error-handling.patch +# PATCH-FIX-UPSTREAM libqt5-fix-build-failure-xcb.patch -- fix build failure in xcb(qtbug#37971) +Patch136: libqt5-fix-build-failure-xcb.patch +# PATCH-FIX-UPSTREAM libqt5-update-bundled-libxkbcommon-version-to-041.patch -- updated bundled libxkbcommon also updated the minimal requirement version at build(qtbug#36281) +Patch137: libqt5-update-bundled-libxkbcommon-version-to-041.patch +# PATCH-FIX-UPSTREAM libqt5-fix-regression-in-key-handling.patch -- introduced new function from libxkbcommon 0.4.1 to fix key handling regression(qtbug#36281) +Patch138: libqt5-fix-regression-in-key-handling.patch +# PATCH-FIX-UPSTREAM libqt5-add-support-for-byte-swapping.patch -- add support for byte swapping(bnc#866709), currently it's at the upstream dev branch +Patch139: libqt5-add-support-for-byte-swapping.patch +# PATCH-FIX-UPSTREAM libqt5-byte-order-byte-is-address0.patch -- the byte order byte is at address 0(bnc#866709), currently it's at the upstream dev branch +Patch140: libqt5-byte-order-byte-is-address0.patch BuildRequires: alsa-devel BuildRequires: cups-devel BuildRequires: fdupes @@ -91,9 +105,9 @@ BuildRequires: pkgconfig(harfbuzz) %endif BuildRequires: pkgconfig(ice) BuildRequires: pkgconfig(sm) -%if 0%{?suse_version} >= 1320 -BuildRequires: pkgconfig(xkbcommon) -BuildRequires: pkgconfig(xkbcommon-x11) +%if 0%{?suse_version} >= 1315 +BuildRequires: pkgconfig(xkbcommon) >= 0.4.1 +BuildRequires: pkgconfig(xkbcommon-x11) >= 0.4.1 %else BuildRequires: xkeyboard-config %endif @@ -130,6 +144,13 @@ handling. %patch131 -p1 %patch132 -p1 %patch133 -p1 +%patch134 -p1 +%patch135 -p1 +%patch136 -p1 +%patch137 -p1 +%patch138 -p1 +%patch139 -p1 +%patch140 -p1 # be sure not to use them rm -r src/3rdparty/{libjpeg,freetype,libpng,zlib} @@ -640,7 +661,7 @@ echo yes | ./configure $platform \ -no-separate-debug-info \ -shared \ -xkb \ -%if 0%{?suse_version} >= 1320 +%if 0%{?suse_version} >= 1315 -system-xkbcommon \ %else -qt-xkbcommon \ @@ -686,9 +707,6 @@ echo yes | ./configure $platform \ -opengl desktop \ %endif -release \ -%ifarch %arm aarch64 - -no-neon \ -%endif -plugin-sql-sqlite -nomake tests \ -plugin-sql-psql -I/usr/include -I/usr/include/pgsql/ -I/usr/include/pgsql/server \ -plugin-sql-odbc \ diff --git a/libqt5-update-bundled-libxkbcommon-version-to-041.patch b/libqt5-update-bundled-libxkbcommon-version-to-041.patch new file mode 100644 index 0000000..fba7531 --- /dev/null +++ b/libqt5-update-bundled-libxkbcommon-version-to-041.patch @@ -0,0 +1,7085 @@ +From bd40a7cc446cafb8c9922d7d19845da580868859 Mon Sep 17 00:00:00 2001 +From: Gatis Paeglis +Date: Fri, 28 Mar 2014 16:22:14 +0100 +Subject: [PATCH] Update bundled libxkbcommon version to 0.4.1 + +This is the latest version, released on Mar 27 2014. It includes: + +https://bugs.freedesktop.org/show_bug.cgi?id=75798 +https://bugs.freedesktop.org/show_bug.cgi?id=75892 + +Required for fixing input when running Qt application on Mac OS X +with XQuartz and for fixing QTBUG-36281. + +Change-Id: Idc4d3c99a4008a10b91ab51c8910b36909974703 +Reviewed-by: Oswald Buddenhagen +Reviewed-by: Lars Knoll +--- + configure | 5 + src/3rdparty/xkbcommon.pri | 5 + src/3rdparty/xkbcommon/NEWS | 43 + + src/3rdparty/xkbcommon/README | 114 ---- + src/3rdparty/xkbcommon/README.md | 109 ++++ + src/3rdparty/xkbcommon/src/context-priv.c | 41 + + src/3rdparty/xkbcommon/src/context.c | 6 + src/3rdparty/xkbcommon/src/context.h | 17 + src/3rdparty/xkbcommon/src/darray.h | 250 +--------- + src/3rdparty/xkbcommon/src/keymap-priv.c | 16 + src/3rdparty/xkbcommon/src/keymap.h | 6 + src/3rdparty/xkbcommon/src/keysym-utf.c | 48 -- + src/3rdparty/xkbcommon/src/keysym.c | 6 + src/3rdparty/xkbcommon/src/scanner-utils.h | 159 ++++++ + src/3rdparty/xkbcommon/src/state.c | 306 ++++++++++-- + src/3rdparty/xkbcommon/src/text.c | 14 + src/3rdparty/xkbcommon/src/utf8.c | 142 ++++++ + src/3rdparty/xkbcommon/src/utf8.h | 36 + + src/3rdparty/xkbcommon/src/utils.h | 22 + src/3rdparty/xkbcommon/src/x11/x11-keymap.c | 73 +-- + src/3rdparty/xkbcommon/src/x11/x11-priv.h | 2 + src/3rdparty/xkbcommon/src/xkb-keymap.c | 33 - + src/3rdparty/xkbcommon/src/xkbcomp/action.c | 427 +++++++----------- + src/3rdparty/xkbcommon/src/xkbcomp/ast-build.c | 59 +- + src/3rdparty/xkbcommon/src/xkbcomp/ast-build.h | 10 + src/3rdparty/xkbcommon/src/xkbcomp/ast.h | 10 + src/3rdparty/xkbcommon/src/xkbcomp/compat.c | 203 -------- + src/3rdparty/xkbcommon/src/xkbcomp/expr.c | 12 + src/3rdparty/xkbcommon/src/xkbcomp/keycodes.c | 81 --- + src/3rdparty/xkbcommon/src/xkbcomp/keymap-dump.c | 91 +-- + src/3rdparty/xkbcommon/src/xkbcomp/keymap.c | 8 + src/3rdparty/xkbcommon/src/xkbcomp/keywords.c | 5 + src/3rdparty/xkbcommon/src/xkbcomp/parser-priv.h | 12 + src/3rdparty/xkbcommon/src/xkbcomp/parser.c | 472 ++++++++++---------- + src/3rdparty/xkbcommon/src/xkbcomp/parser.h | 2 + src/3rdparty/xkbcommon/src/xkbcomp/rules.c | 259 +++------- + src/3rdparty/xkbcommon/src/xkbcomp/scanner-utils.h | 145 ------ + src/3rdparty/xkbcommon/src/xkbcomp/scanner.c | 54 -- + src/3rdparty/xkbcommon/src/xkbcomp/symbols.c | 129 ++--- + src/3rdparty/xkbcommon/src/xkbcomp/types.c | 121 ----- + src/3rdparty/xkbcommon/src/xkbcomp/vmod.c | 63 ++ + src/3rdparty/xkbcommon/src/xkbcomp/vmod.h | 3 + src/3rdparty/xkbcommon/xkbcommon/xkbcommon-compat.h | 4 + src/3rdparty/xkbcommon/xkbcommon/xkbcommon-x11.h | 8 + src/3rdparty/xkbcommon/xkbcommon/xkbcommon.h | 140 ++++- + src/plugins/platforms/xcb/qxcbkeyboard.h | 3 + 46 files changed, 1790 insertions(+), 1984 deletions(-) + delete mode 100644 src/3rdparty/xkbcommon/README + create mode 100644 src/3rdparty/xkbcommon/README.md + create mode 100644 src/3rdparty/xkbcommon/src/scanner-utils.h + create mode 100644 src/3rdparty/xkbcommon/src/utf8.c + create mode 100644 src/3rdparty/xkbcommon/src/utf8.h + delete mode 100644 src/3rdparty/xkbcommon/src/xkbcomp/scanner-utils.h + +--- a/configure ++++ b/configure +@@ -5327,11 +5327,12 @@ if [ "$CFG_KMS" != "no" ]; then + fi + + # Detect libxkbcommon ++MIN_REQ_XKBCOMMON="0.4.1" + ORIG_CFG_XKBCOMMON="$CFG_XKBCOMMON" + # currently only xcb platform plugin supports building xkbcommon + if [ "$CFG_XCB" != "no" ]; then + if [ "$CFG_XKBCOMMON" = "auto" ] || [ "$CFG_XKBCOMMON" = "system" ]; then +- if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists "xkbcommon xkbcommon-x11 >= 0.4.0" 2>/dev/null; then ++ if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists "xkbcommon xkbcommon-x11 >= $MIN_REQ_XKBCOMMON" 2>/dev/null; then + QMAKE_CFLAGS_XKBCOMMON="`$PKG_CONFIG --cflags xkbcommon xkbcommon-x11 2>/dev/null`" + QMAKE_LIBS_XKBCOMMON="`$PKG_CONFIG --libs xkbcommon xkbcommon-x11 2>/dev/null`" + +@@ -6840,7 +6841,7 @@ if [ "$CFG_OPENSSL" = "linked" ] && [ "$ + echo + fi + if [ "$ORIG_CFG_XKBCOMMON" != qt ] && [ "$CFG_XKBCOMMON" = qt ]; then +- echo "NOTE: libxkbcommon and libxkbcommon-x11 0.4.0 or higher not found on the system, will use " ++ echo "NOTE: libxkbcommon and libxkbcommon-x11 $MIN_REQ_XKBCOMMON or higher not found on the system, will use " + echo "the bundled version from 3rd party directory." + fi + if [ "$CFG_XKBCOMMON" = "qt" ] && [ "$CFG_XKB_CONFIG_ROOT" = "not found" ]; then +--- a/src/3rdparty/xkbcommon.pri ++++ b/src/3rdparty/xkbcommon.pri +@@ -26,7 +26,8 @@ SOURCES += \ + $$PWD/xkbcommon/src/text.c \ + $$PWD/xkbcommon/src/context-priv.c \ + $$PWD/xkbcommon/src/keymap-priv.c \ +- $$PWD/xkbcommon/src/utils.c ++ $$PWD/xkbcommon/src/utils.c \ ++ $$PWD/xkbcommon/src/utf8.c + + SOURCES += \ + $$PWD/xkbcommon/src/xkbcomp/action.c \ +@@ -54,7 +55,7 @@ SOURCES += \ + SOURCES += \ + $$PWD/xkbcommon/src/x11/util.c \ + $$PWD/xkbcommon/src/x11/x11-keymap.c \ # renamed: keymap.c -> x11-keymap.c +- $$PWD/xkbcommon/src/x11/x11-state.c # renamed: state.c -> x11-keymap.c ++ $$PWD/xkbcommon/src/x11/x11-state.c # renamed: state.c -> x11-state.c + } + + TR_EXCLUDE += $$PWD/* +--- a/src/3rdparty/xkbcommon/NEWS ++++ b/src/3rdparty/xkbcommon/NEWS +@@ -1,3 +1,46 @@ ++libxkbcommon 0.4.1 ++================== ++ ++- Converted README to markdown and added a Quick Guide to the ++ documentation, which breezes through the most common parts of ++ xkbcommon. ++ ++- Added two new functions, xkb_state_key_get_utf{8,32}(). They ++ combine the operations of xkb_state_key_get_syms() and ++ xkb_keysym_to_utf{8,32}(), and provide a nicer interface for it ++ (espcially for multiple-keysyms-per-level). ++ ++- The xkb_state_key_get_utf{8,32}() functions now apply Control ++ transformation: when the Control modifier is active, the string ++ is converted to an appropriate control character. ++ This matches the behavior of libX11's XLookupString(3), and ++ required by the XKB specification: ++ http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier ++ ++ https://bugs.freedesktop.org/show_bug.cgi?id=75892 ++ ++- The consumed modifiers for a key are now calculated similarly ++ to libX11. The previous behavior caused a bug where Shift would ++ not cancel an active Caps Lock. ++ ++- Make xkbcommon-x11 work with the keymap reported by the XQuartz ++ X server. ++ ++ https://bugs.freedesktop.org/show_bug.cgi?id=75798 ++ ++- Reduce memory usage during keymap compilation some more. ++ ++- New API: ++ xkb_state_key_get_consumed_mods() ++ xkb_state_key_get_utf8() ++ xkb_state_key_get_utf32() ++ ++- Deprecated API: ++ XKB_MAP_COMPILE_PLACEHOLDER, XKB_MAP_NO_FLAGS ++ use XKB_KEYMAP_NO_FLAGS instead. ++ ++- Bug fixes. ++ + libxkbcommon 0.4.0 + ================== + +--- a/src/3rdparty/xkbcommon/README ++++ /dev/null +@@ -1,114 +0,0 @@ +-Overview {#mainpage} +-======== +- +-xkbcommon is a keymap compiler and support library which processes a +-reduced subset of keymaps as defined by the XKB specification. Primarily, +-a keymap is created from a set of Rules/Model/Layout/Variant/Options names, +-processed through an XKB ruleset, and compiled into a struct xkb_keymap, +-which is the base type for all xkbcommon operations. +- +-From an xkb_keymap, an xkb_state object is created which holds the current +-state of all modifiers, groups, LEDs, etc, relating to that keymap. All +-key events must be fed into the xkb_state object using xkb_state_update_key(). +-Once this is done, the xkb_state object will be properly updated, and the +-keysyms to use can be obtained with xkb_state_key_get_syms(). +- +-libxkbcommon does not distribute a dataset itself, other than for testing +-purposes. The most common dataset is xkeyboard-config, as used by all +-current distributions for their X11 XKB data. More information on +-xkeyboard-config is available here: +- http://www.freedesktop.org/wiki/Software/XKeyboardConfig +- +- +-API +-=== +- +-While xkbcommon's API is somewhat derived from the classic XKB API as found +-in and friends, it has been substantially reworked to +-expose fewer internal details to clients. The supported API is available +-in the files. Additional support is provided for +-X11 (XCB) clients, in the xkbcommon-x11 library, . +- +-The xkbcommon API and ABI are stable. We will attempt to not break ABI during +-a minor release series, so applications written against 0.1.0 should be +-completely compatible with 0.5.3, but not necessarily with 1.0.0. However, new +-symbols may be introduced in any release. Thus, anyone packaging xkbcommon +-should make sure any package depending on it depends on a release greater than +-or equal to the version it was built against (or earlier, if it doesn't use +-any newly-introduced symbols), but less than the next major release. +- +- +-Relation to X11 +-=============== +- +-Relative to the XKB 1.1 specification implemented in current X servers, +-xkbcommon has removed support for some parts of the specification which +-introduced unnecessary complications. Many of these removals were in fact +-not implemented, or half-implemented at best, as well as being totally +-unused in the standard dataset. +- +-Notable removals: +- - geometry support +- + there were very few geometry definitions available, and while +- xkbcommon was responsible for parsing this insanely complex format, +- it never actually did anything with it +- + hopefully someone will develop a companion library which supports +- keyboard geometries in a more useful format +- - KcCGST (keycodes/compat/geometry/symbols/types) API +- + use RMLVO instead; KcCGST is now an implementation detail +- + including pre-defined keymap files +- - XKM support +- + may come in an optional X11 support/compatibility library +- - around half of the interpret actions +- + pointer device, message and redirect actions in particular +- - non-virtual modifiers +- + core and virtual modifiers have been collapsed into the same +- namespace, with a 'significant' flag that largely parallels the +- core/virtual split +- - radio groups +- + completely unused in current keymaps, never fully implemented +- - overlays +- + almost completely unused in current keymaps +- - key behaviors +- + used to implement radio groups and overlays, and to deal with things +- like keys that physically lock; unused in current keymaps +- - indicator behaviours such as LED-controls-key +- + the only supported LED behaviour is key-controls-LED; again this +- was never really used in current keymaps +- +-Notable additions: +- - 32-bit keycodes +- - extended number of modifiers +- - extended number of groups +- - multiple keysyms per level +- + this requires incompatible dataset changes, such that X11 would +- not be able to parse these +- +- +-Development +-=========== +- +-An extremely rudimentary homepage can be found at: +- http://xkbcommon.org +- +-xkbcommon is maintained in git at github.com: +- https://github.com/xkbcommon/libxkbcommon +- +-Patches are always welcome, and may be sent to either xorg-devel@lists.x.org, +-or wayland-devel@lists.freedesktop.org. +- +-Bugs are tracked in Bugzilla at: +- https://bugs.freedesktop.org/describecomponents.cgi?product=libxkbcommon +-Or in github at: +- https://github.com/xkbcommon/libxkbcommon/issues +- +-The maintainers are Daniel Stone and Ran Benita, who can be reached at: +- +- +- +- +-Credits +-======= +- +-Many thanks are due to Dan Nicholson for his heroic work in getting xkbcommon +-off the ground initially. +--- /dev/null ++++ b/src/3rdparty/xkbcommon/README.md +@@ -0,0 +1,109 @@ ++# libxkbcommon ++ ++xkbcommon is a keymap compiler and support library which processes a ++reduced subset of keymaps as defined by the XKB specification. Primarily, ++a keymap is created from a set of Rules/Model/Layout/Variant/Options names, ++processed through an XKB ruleset, and compiled into a struct xkb_keymap, ++which is the base type for all xkbcommon operations. ++ ++From an xkb_keymap, an xkb_state object is created which holds the current ++state of all modifiers, groups, LEDs, etc, relating to that keymap. All ++key events must be fed into the xkb_state object using xkb_state_update_key(). ++Once this is done, the xkb_state object will be properly updated, and the ++keysyms to use can be obtained with xkb_state_key_get_syms(). ++ ++libxkbcommon does not distribute a dataset itself, other than for testing ++purposes. The most common dataset is xkeyboard-config, as used by all ++current distributions for their X11 XKB data. More information on ++xkeyboard-config is available here: ++ http://www.freedesktop.org/wiki/Software/XKeyboardConfig ++ ++## Quick Guide ++ ++See [Quick Guide](doc/quick-guide.md). ++ ++## API ++ ++While xkbcommon's API is somewhat derived from the classic XKB API as found ++in X11/extensions/XKB.h and friends, it has been substantially reworked to ++expose fewer internal details to clients. The supported API is available ++in the xkbcommon/xkbcommon-*.h files. Additional support is provided for ++X11 (XCB) clients, in the xkbcommon-x11 library, xkbcommon/xkbcommon-x11.h. ++ ++The xkbcommon API and ABI are stable. We will attempt to not break ABI during ++a minor release series, so applications written against 0.1.0 should be ++completely compatible with 0.5.3, but not necessarily with 1.0.0. However, new ++symbols may be introduced in any release. Thus, anyone packaging xkbcommon ++should make sure any package depending on it depends on a release greater than ++or equal to the version it was built against (or earlier, if it doesn't use ++any newly-introduced symbols), but less than the next major release. ++ ++## Relation to X11 ++ ++Relative to the XKB 1.1 specification implemented in current X servers, ++xkbcommon has removed support for some parts of the specification which ++introduced unnecessary complications. Many of these removals were in fact ++not implemented, or half-implemented at best, as well as being totally ++unused in the standard dataset. ++ ++Notable removals: ++- geometry support ++ + there were very few geometry definitions available, and while ++ xkbcommon was responsible for parsing this insanely complex format, ++ it never actually did anything with it ++ + hopefully someone will develop a companion library which supports ++ keyboard geometries in a more useful format ++- KcCGST (keycodes/compat/geometry/symbols/types) API ++ + use RMLVO instead; KcCGST is now an implementation detail ++ + including pre-defined keymap files ++- XKM support ++ + may come in an optional X11 support/compatibility library ++- around half of the interpret actions ++ + pointer device, message and redirect actions in particular ++- non-virtual modifiers ++ + core and virtual modifiers have been collapsed into the same ++ namespace, with a 'significant' flag that largely parallels the ++ core/virtual split ++- radio groups ++ + completely unused in current keymaps, never fully implemented ++- overlays ++ + almost completely unused in current keymaps ++- key behaviors ++ + used to implement radio groups and overlays, and to deal with things ++ like keys that physically lock; unused in current keymaps ++- indicator behaviours such as LED-controls-key ++ + the only supported LED behaviour is key-controls-LED; again this ++ was never really used in current keymaps ++ ++Notable additions: ++- 32-bit keycodes ++- extended number of modifiers ++- extended number of groups ++- multiple keysyms per level ++ + this requires incompatible dataset changes, such that X11 would ++ not be able to parse these ++ ++## Development ++ ++An extremely rudimentary homepage can be found at ++ http://xkbcommon.org ++ ++xkbcommon is maintained in git at ++ https://github.com/xkbcommon/libxkbcommon ++ ++Patches are always welcome, and may be sent to either ++ or ++ ++Bugs are also welcome, and may be reported either at ++ Bugzilla https://bugs.freedesktop.org/describecomponents.cgi?product=libxkbcommon ++or ++ Github https://github.com/xkbcommon/libxkbcommon/issues ++ ++The maintainers are ++- Daniel Stone ++- Ran Benita ++ ++## Credits ++ ++Many thanks are due to Dan Nicholson for his heroic work in getting xkbcommon ++off the ground initially. +--- a/src/3rdparty/xkbcommon/src/context-priv.c ++++ b/src/3rdparty/xkbcommon/src/context-priv.c +@@ -112,60 +112,79 @@ xkb_context_get_buffer(struct xkb_contex + #define DEFAULT_XKB_OPTIONS NULL + #endif + +-const char * ++static const char * + xkb_context_get_default_rules(struct xkb_context *ctx) + { + const char *env = NULL; + + if (ctx->use_environment_names) +- env = getenv("XKB_DEFAULT_RULES"); ++ env = secure_getenv("XKB_DEFAULT_RULES"); + + return env ? env : DEFAULT_XKB_RULES; + } + +-const char * ++static const char * + xkb_context_get_default_model(struct xkb_context *ctx) + { + const char *env = NULL; + + if (ctx->use_environment_names) +- env = getenv("XKB_DEFAULT_MODEL"); ++ env = secure_getenv("XKB_DEFAULT_MODEL"); + + return env ? env : DEFAULT_XKB_MODEL; + } + +-const char * ++static const char * + xkb_context_get_default_layout(struct xkb_context *ctx) + { + const char *env = NULL; + + if (ctx->use_environment_names) +- env = getenv("XKB_DEFAULT_LAYOUT"); ++ env = secure_getenv("XKB_DEFAULT_LAYOUT"); + + return env ? env : DEFAULT_XKB_LAYOUT; + } + +-const char * ++static const char * + xkb_context_get_default_variant(struct xkb_context *ctx) + { + const char *env = NULL; +- const char *layout = getenv("XKB_DEFAULT_VARIANT"); ++ const char *layout = secure_getenv("XKB_DEFAULT_LAYOUT"); + + /* We don't want to inherit the variant if they haven't also set a + * layout, since they're so closely paired. */ + if (layout && ctx->use_environment_names) +- env = getenv("XKB_DEFAULT_VARIANT"); ++ env = secure_getenv("XKB_DEFAULT_VARIANT"); + + return env ? env : DEFAULT_XKB_VARIANT; + } + +-const char * ++static const char * + xkb_context_get_default_options(struct xkb_context *ctx) + { + const char *env = NULL; + + if (ctx->use_environment_names) +- env = getenv("XKB_DEFAULT_OPTIONS"); ++ env = secure_getenv("XKB_DEFAULT_OPTIONS"); + + return env ? env : DEFAULT_XKB_OPTIONS; + } ++ ++void ++xkb_context_sanitize_rule_names(struct xkb_context *ctx, ++ struct xkb_rule_names *rmlvo) ++{ ++ if (isempty(rmlvo->rules)) ++ rmlvo->rules = xkb_context_get_default_rules(ctx); ++ if (isempty(rmlvo->model)) ++ rmlvo->model = xkb_context_get_default_model(ctx); ++ /* Layout and variant are tied together, so don't try to use one from ++ * the caller and one from the environment. */ ++ if (isempty(rmlvo->layout)) { ++ rmlvo->layout = xkb_context_get_default_layout(ctx); ++ rmlvo->variant = xkb_context_get_default_variant(ctx); ++ } ++ /* Options can be empty, so respect that if passed in. */ ++ if (rmlvo->options == NULL) ++ rmlvo->options = xkb_context_get_default_options(ctx); ++} +--- a/src/3rdparty/xkbcommon/src/context.c ++++ b/src/3rdparty/xkbcommon/src/context.c +@@ -82,7 +82,7 @@ xkb_context_include_path_append_default( + + ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT); + +- home = getenv("HOME"); ++ home = secure_getenv("HOME"); + if (!home) + return ret; + err = asprintf(&user_path, "%s/.xkb", home); +@@ -252,11 +252,11 @@ xkb_context_new(enum xkb_context_flags f + ctx->log_verbosity = 0; + + /* Environment overwrites defaults. */ +- env = getenv("XKB_LOG_LEVEL"); ++ env = secure_getenv("XKB_LOG_LEVEL"); + if (env) + xkb_context_set_log_level(ctx, log_level(env)); + +- env = getenv("XKB_LOG_VERBOSITY"); ++ env = secure_getenv("XKB_LOG_VERBOSITY"); + if (env) + xkb_context_set_log_verbosity(ctx, log_verbosity(env)); + +--- a/src/3rdparty/xkbcommon/src/context.h ++++ b/src/3rdparty/xkbcommon/src/context.h +@@ -91,20 +91,9 @@ ATTR_PRINTF(4, 5) void + xkb_log(struct xkb_context *ctx, enum xkb_log_level level, int verbosity, + const char *fmt, ...); + +-const char * +-xkb_context_get_default_rules(struct xkb_context *ctx); +- +-const char * +-xkb_context_get_default_model(struct xkb_context *ctx); +- +-const char * +-xkb_context_get_default_layout(struct xkb_context *ctx); +- +-const char * +-xkb_context_get_default_variant(struct xkb_context *ctx); +- +-const char * +-xkb_context_get_default_options(struct xkb_context *ctx); ++void ++xkb_context_sanitize_rule_names(struct xkb_context *ctx, ++ struct xkb_rule_names *rmlvo); + + /* + * The format is not part of the argument list in order to avoid the +--- a/src/3rdparty/xkbcommon/src/darray.h ++++ b/src/3rdparty/xkbcommon/src/darray.h +@@ -23,93 +23,15 @@ + #ifndef CCAN_DARRAY_H + #define CCAN_DARRAY_H + ++/* Originally taken from: http://ccodearchive.net/info/darray.html ++ * But modified for libxkbcommon. */ ++ + #include + #include ++#include ++#include + +-/* +- * SYNOPSIS +- * +- * Life cycle of a darray (dynamically-allocated array): +- * +- * darray(int) a = darray_new(); +- * darray_free(a); +- * +- * struct {darray(int) a;} foo; +- * darray_init(foo.a); +- * darray_free(foo.a); +- * +- * Typedefs for darrays of common types: +- * +- * darray_char, darray_schar, darray_uchar +- * darray_short, darray_int, darray_long +- * darray_ushort, darray_uint, darray_ulong +- * +- * Access: +- * +- * T darray_item(darray(T) arr, size_t index); +- * size_t darray_size(darray(T) arr); +- * size_t darray_alloc(darray(T) arr); +- * bool darray_empty(darray(T) arr); +- * +- * // Access raw memory, starting from the item in offset. +- * // Not safe, be careful, etc. +- * T* darray_mem(darray(T) arr, size_t offset); +- * +- * Insertion (single item): +- * +- * void darray_append(darray(T) arr, T item); +- * void darray_prepend(darray(T) arr, T item); +- * void darray_push(darray(T) arr, T item); // same as darray_append +- * +- * Insertion (multiple items): +- * +- * void darray_append_items(darray(T) arr, T *items, size_t count); +- * void darray_prepend_items(darray(T) arr, T *items, size_t count); +- * +- * void darray_appends(darray(T) arr, [T item, [...]]); +- * void darray_prepends(darray(T) arr, [T item, [...]]); +- * +- * Removal: +- * +- * T darray_pop(darray(T) arr | darray_size(arr) != 0); +- * T* darray_pop_check(darray(T*) arr); +- * +- * Replacement: +- * +- * void darray_from_items(darray(T) arr, T *items, size_t count); +- * void darray_from_c(darray(T) arr, T c_array[N]); +- * +- * String buffer: +- * +- * void darray_append_string(darray(char) arr, const char *str); +- * void darray_append_lit(darray(char) arr, char stringLiteral[N+1]); +- * +- * void darray_prepend_string(darray(char) arr, const char *str); +- * void darray_prepend_lit(darray(char) arr, char stringLiteral[N+1]); +- * +- * void darray_from_string(darray(T) arr, const char *str); +- * void darray_from_lit(darray(char) arr, char stringLiteral[N+1]); +- * +- * Size management: +- * +- * void darray_resize(darray(T) arr, size_t newSize); +- * void darray_resize0(darray(T) arr, size_t newSize); +- * +- * void darray_realloc(darray(T) arr, size_t newAlloc); +- * void darray_growalloc(darray(T) arr, size_t newAlloc); +- * +- * Traversal: +- * +- * darray_foreach(T *&i, darray(T) arr) {...} +- * darray_foreach_reverse(T *&i, darray(T) arr) {...} +- * +- * Except for darray_foreach and darray_foreach_reverse, +- * all macros evaluate their non-darray arguments only once. +- */ +- +-/*** Life cycle ***/ +- +-#define darray(type) struct { type *item; size_t size; size_t alloc; } ++#define darray(type) struct { type *item; unsigned size; unsigned alloc; } + + #define darray_new() { 0, 0, 0 } + +@@ -118,7 +40,8 @@ + } while (0) + + #define darray_free(arr) do { \ +- free((arr).item); darray_init(arr); \ ++ free((arr).item); \ ++ darray_init(arr); \ + } while (0) + + /* +@@ -154,11 +77,8 @@ typedef darray (unsigned long) darray_u + + #define darray_item(arr, i) ((arr).item[i]) + #define darray_size(arr) ((arr).size) +-#define darray_alloc(arr) ((arr).alloc) + #define darray_empty(arr) ((arr).size == 0) +- + #define darray_mem(arr, offset) ((arr).item + (offset)) +-#define darray_same(arr1, arr2) ((arr1).item == (arr2).item) + + /*** Insertion (single item) ***/ + +@@ -167,74 +87,20 @@ typedef darray (unsigned long) darray_u + (arr).item[(arr).size - 1] = (__VA_ARGS__); \ + } while (0) + +-#define darray_prepend(arr, ...) do { \ +- darray_resize(arr, (arr).size + 1); \ +- memmove((arr).item + 1, (arr).item, \ +- ((arr).size - 1) * sizeof(*(arr).item)); \ +- (arr).item[0] = (__VA_ARGS__); \ +-} while (0) +- +-#define darray_push(arr, ...) darray_append(arr, __VA_ARGS__) +- + /*** Insertion (multiple items) ***/ + + #define darray_append_items(arr, items, count) do { \ +- size_t __count = (count), __oldSize = (arr).size; \ ++ unsigned __count = (count), __oldSize = (arr).size; \ + darray_resize(arr, __oldSize + __count); \ + memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \ + } while (0) + +-#define darray_prepend_items(arr, items, count) do { \ +- size_t __count = (count), __oldSize = (arr).size; \ +- darray_resize(arr, __count + __oldSize); \ +- memmove((arr).item + __count, (arr).item, \ +- __oldSize * sizeof(*(arr).item)); \ +- memcpy((arr).item, items, __count * sizeof(*(arr).item)); \ +-} while (0) +- +-#define darray_append_items_nullterminate(arr, items, count) do { \ +- size_t __count = (count), __oldSize = (arr).size; \ +- darray_resize(arr, __oldSize + __count + 1); \ +- memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \ +- (arr).item[--(arr).size] = 0; \ +-} while (0) +- +-#define darray_prepend_items_nullterminate(arr, items, count) do { \ +- size_t __count = (count), __oldSize = (arr).size; \ +- darray_resize(arr, __count + __oldSize + 1); \ +- memmove((arr).item + __count, (arr).item, \ +- __oldSize * sizeof(*(arr).item)); \ +- memcpy((arr).item, items, __count * sizeof(*(arr).item)); \ +- (arr).item[--(arr).size] = 0; \ +-} while (0) +- +-#define darray_appends_t(arr, type, ...) do { \ +- type __src[] = { __VA_ARGS__ }; \ +- darray_append_items(arr, __src, sizeof(__src) / sizeof(*__src)); \ +-} while (0) +- +-#define darray_prepends_t(arr, type, ...) do { \ +- type __src[] = { __VA_ARGS__ }; \ +- darray_prepend_items(arr, __src, sizeof(__src) / sizeof(*__src)); \ +-} while (0) +- +-/*** Removal ***/ +- +-/* Warning: Do not call darray_pop on an empty darray. */ +-#define darray_pop(arr) ((arr).item[--(arr).size]) +-#define darray_pop_check(arr) ((arr).size ? darray_pop(arr) : NULL) +- +-/*** Replacement ***/ +- + #define darray_from_items(arr, items, count) do { \ +- size_t __count = (count); \ ++ unsigned __count = (count); \ + darray_resize(arr, __count); \ + memcpy((arr).item, items, __count * sizeof(*(arr).item)); \ + } while (0) + +-#define darray_from_c(arr, c_array) \ +- darray_from_items(arr, c_array, sizeof(c_array) / sizeof(*(c_array))) +- + #define darray_copy(arr_to, arr_from) \ + darray_from_items((arr_to), (arr_from).item, (arr_from).size) + +@@ -251,24 +117,20 @@ typedef darray (unsigned long) darray_u + (arr).size--; \ + } while (0) + +-#define darray_prepend_string(arr, str) do { \ +- const char *__str = (str); \ +- darray_prepend_items_nullterminate(arr, __str, strlen(__str)); \ +-} while (0) +- +-#define darray_prepend_lit(arr, stringLiteral) \ +- darray_prepend_items_nullterminate(arr, stringLiteral, \ +- sizeof(stringLiteral) - 1) +- +-#define darray_from_string(arr, str) do { \ +- const char *__str = (str); \ +- darray_from_items(arr, __str, strlen(__str) + 1); \ +- (arr).size--; \ ++#define darray_appends_nullterminate(arr, items, count) do { \ ++ unsigned __count = (count), __oldSize = (arr).size; \ ++ darray_resize(arr, __oldSize + __count + 1); \ ++ memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \ ++ (arr).item[--(arr).size] = 0; \ + } while (0) + +-#define darray_from_lit(arr, stringLiteral) do { \ +- darray_from_items(arr, stringLiteral, sizeof(stringLiteral)); \ +- (arr).size--; \ ++#define darray_prepends_nullterminate(arr, items, count) do { \ ++ unsigned __count = (count), __oldSize = (arr).size; \ ++ darray_resize(arr, __count + __oldSize + 1); \ ++ memmove((arr).item + __count, (arr).item, \ ++ __oldSize * sizeof(*(arr).item)); \ ++ memcpy((arr).item, items, __count * sizeof(*(arr).item)); \ ++ (arr).item[--(arr).size] = 0; \ + } while (0) + + /*** Size management ***/ +@@ -277,7 +139,7 @@ typedef darray (unsigned long) darray_u + darray_growalloc(arr, (arr).size = (newSize)) + + #define darray_resize0(arr, newSize) do { \ +- size_t __oldSize = (arr).size, __newSize = (newSize); \ ++ unsigned __oldSize = (arr).size, __newSize = (newSize); \ + (arr).size = __newSize; \ + if (__newSize > __oldSize) { \ + darray_growalloc(arr, __newSize); \ +@@ -292,14 +154,16 @@ typedef darray (unsigned long) darray_u + } while (0) + + #define darray_growalloc(arr, need) do { \ +- size_t __need = (need); \ ++ unsigned __need = (need); \ + if (__need > (arr).alloc) \ +- darray_realloc(arr, darray_next_alloc((arr).alloc, __need)); \ ++ darray_realloc(arr, darray_next_alloc((arr).alloc, __need, \ ++ sizeof(*(arr).item))); \ + } while (0) + +-static inline size_t +-darray_next_alloc(size_t alloc, size_t need) ++static inline unsigned ++darray_next_alloc(unsigned alloc, unsigned need, unsigned itemSize) + { ++ assert(need < UINT_MAX / itemSize / 2); /* Overflow. */ + if (alloc == 0) + alloc = 4; + while (alloc < need) +@@ -309,11 +173,6 @@ darray_next_alloc(size_t alloc, size_t n + + /*** Traversal ***/ + +-/* +- * darray_foreach(T *&i, darray(T) arr) {...} +- * +- * Traverse a darray. `i` must be declared in advance as a pointer to an item. +- */ + #define darray_foreach(i, arr) \ + for ((i) = &(arr).item[0]; (i) < &(arr).item[(arr).size]; (i)++) + +@@ -331,58 +190,7 @@ darray_next_alloc(size_t alloc, size_t n + (idx) < (arr).size; \ + (idx)++, (val)++) + +-/* +- * darray_foreach_reverse(T *&i, darray(T) arr) {...} +- * +- * Like darray_foreach, but traverse in reverse order. +- */ + #define darray_foreach_reverse(i, arr) \ + for ((i) = &(arr).item[(arr).size]; (i)-- > &(arr).item[0]; ) + + #endif /* CCAN_DARRAY_H */ +- +-/* +- * +- * darray_growalloc(arr, newAlloc) sees if the darray can currently hold newAlloc items; +- * if not, it increases the alloc to satisfy this requirement, allocating slack +- * space to avoid having to reallocate for every size increment. +- * +- * darray_from_string(arr, str) copies a string to an darray_char. +- * +- * darray_push(arr, item) pushes an item to the end of the darray. +- * darray_pop(arr) pops it back out. Be sure there is at least one item in the darray before calling. +- * darray_pop_check(arr) does the same as darray_pop, but returns NULL if there are no more items left in the darray. +- * +- * darray_make_room(arr, room) ensures there's 'room' elements of space after the end of the darray, and it returns a pointer to this space. +- * Currently requires HAVE_STATEMENT_EXPR, but I plan to remove this dependency by creating an inline function. +- * +- * The following require HAVE_TYPEOF==1 : +- * +- * darray_appends(arr, item0, item1...) appends a collection of comma-delimited items to the darray. +- * darray_prepends(arr, item0, item1...) prepends a collection of comma-delimited items to the darray.\ +- * +- * +- * Examples: +- * +- * darray(int) arr; +- * int *i; +- * +- * darray_appends(arr, 0,1,2,3,4); +- * darray_appends(arr, -5,-4,-3,-2,-1); +- * darray_foreach(i, arr) +- * printf("%d ", *i); +- * printf("\n"); +- * +- * darray_free(arr); +- * +- * +- * typedef struct {int n,d;} Fraction; +- * darray(Fraction) fractions; +- * Fraction *i; +- * +- * darray_appends(fractions, {3,4}, {3,5}, {2,1}); +- * darray_foreach(i, fractions) +- * printf("%d/%d\n", i->n, i->d); +- * +- * darray_free(fractions); +- */ +--- a/src/3rdparty/xkbcommon/src/keymap-priv.c ++++ b/src/3rdparty/xkbcommon/src/keymap-priv.c +@@ -30,12 +30,7 @@ static void + update_builtin_keymap_fields(struct xkb_keymap *keymap) + { + struct xkb_context *ctx = keymap->ctx; +- +- /* +- * Add predefined (AKA real, core, X11) modifiers. +- * The order is important! +- */ +- darray_appends_t(keymap->mods, struct xkb_mod, ++ const struct xkb_mod builtin_mods[] = { + { .name = xkb_atom_intern_literal(ctx, "Shift"), .type = MOD_REAL }, + { .name = xkb_atom_intern_literal(ctx, "Lock"), .type = MOD_REAL }, + { .name = xkb_atom_intern_literal(ctx, "Control"), .type = MOD_REAL }, +@@ -43,7 +38,14 @@ update_builtin_keymap_fields(struct xkb_ + { .name = xkb_atom_intern_literal(ctx, "Mod2"), .type = MOD_REAL }, + { .name = xkb_atom_intern_literal(ctx, "Mod3"), .type = MOD_REAL }, + { .name = xkb_atom_intern_literal(ctx, "Mod4"), .type = MOD_REAL }, +- { .name = xkb_atom_intern_literal(ctx, "Mod5"), .type = MOD_REAL }); ++ { .name = xkb_atom_intern_literal(ctx, "Mod5"), .type = MOD_REAL }, ++ }; ++ ++ /* ++ * Add predefined (AKA real, core, X11) modifiers. ++ * The order is important! ++ */ ++ darray_append_items(keymap->mods, builtin_mods, ARRAY_SIZE(builtin_mods)); + } + + struct xkb_keymap * +--- a/src/3rdparty/xkbcommon/src/keymap.h ++++ b/src/3rdparty/xkbcommon/src/keymap.h +@@ -146,7 +146,7 @@ enum xkb_action_flags { + ACTION_ABSOLUTE_SWITCH = (1 << 5), + ACTION_ABSOLUTE_X = (1 << 6), + ACTION_ABSOLUTE_Y = (1 << 7), +- ACTION_NO_ACCEL = (1 << 8), ++ ACTION_ACCEL = (1 << 8), + ACTION_SAME_SCREEN = (1 << 9), + }; + +@@ -223,7 +223,7 @@ struct xkb_pointer_button_action { + enum xkb_action_type type; + enum xkb_action_flags flags; + uint8_t count; +- int8_t button; ++ uint8_t button; + }; + + struct xkb_private_action { +@@ -262,10 +262,10 @@ struct xkb_key_type { + struct xkb_sym_interpret { + xkb_keysym_t sym; + enum xkb_match_operation match; +- bool level_one_only; + xkb_mod_mask_t mods; + xkb_mod_index_t virtual_mod; + union xkb_action action; ++ bool level_one_only; + bool repeat; + }; + +--- a/src/3rdparty/xkbcommon/src/keysym-utf.c ++++ b/src/3rdparty/xkbcommon/src/keysym-utf.c +@@ -37,6 +37,7 @@ + + #include "xkbcommon/xkbcommon.h" + #include "utils.h" ++#include "utf8.h" + + /* We don't use the uint32_t types here, to save some space. */ + struct codepair { +@@ -838,15 +839,15 @@ static const struct codepair keysymtab[] + static uint32_t + bin_search(const struct codepair *table, size_t length, xkb_keysym_t keysym) + { +- int first = 0; +- int last = length; ++ size_t first = 0; ++ size_t last = length; + + if (keysym < table[0].keysym || keysym > table[length].keysym) + return 0; + + /* binary search in table */ + while (last >= first) { +- int mid = (first + last) / 2; ++ size_t mid = (first + last) / 2; + if (table[mid].keysym < keysym) + first = mid + 1; + else if (table[mid].keysym > keysym) +@@ -912,47 +913,6 @@ xkb_keysym_to_utf32(xkb_keysym_t keysym) + * Author: Rob Bradford + */ + +-static int +-utf32_to_utf8(uint32_t unichar, char *buffer) +-{ +- int count, shift, length; +- uint8_t head; +- +- if (unichar <= 0x007f) { +- buffer[0] = unichar; +- buffer[1] = '\0'; +- return 2; +- } +- else if (unichar <= 0x07FF) { +- length = 2; +- head = 0xc0; +- } +- else if (unichar <= 0xffff) { +- length = 3; +- head = 0xe0; +- } +- else if (unichar <= 0x1fffff) { +- length = 4; +- head = 0xf0; +- } +- else if (unichar <= 0x3ffffff) { +- length = 5; +- head = 0xf8; +- } +- else { +- length = 6; +- head = 0xfc; +- } +- +- for (count = length - 1, shift = 0; count > 0; count--, shift += 6) +- buffer[count] = 0x80 | ((unichar >> shift) & 0x3f); +- +- buffer[0] = head | ((unichar >> shift) & 0x3f); +- buffer[length] = '\0'; +- +- return length + 1; +-} +- + XKB_EXPORT int + xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size) + { +--- a/src/3rdparty/xkbcommon/src/keysym.c ++++ b/src/3rdparty/xkbcommon/src/keysym.c +@@ -64,7 +64,11 @@ compare_by_keysym(const void *a, const v + { + const xkb_keysym_t *key = a; + const struct name_keysym *entry = b; +- return *key - (int32_t) entry->keysym; ++ if (*key < entry->keysym) ++ return -1; ++ if (*key > entry->keysym) ++ return 1; ++ return 0; + } + + static int +--- /dev/null ++++ b/src/3rdparty/xkbcommon/src/scanner-utils.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright © 2012 Ran Benita ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef XKBCOMP_SCANNER_UTILS_H ++#define XKBCOMP_SCANNER_UTILS_H ++ ++/* Point to some substring in the file; used to avoid copying. */ ++struct sval { ++ const char *start; ++ unsigned int len; ++}; ++typedef darray(struct sval) darray_sval; ++ ++static inline bool ++svaleq(struct sval s1, struct sval s2) ++{ ++ return s1.len == s2.len && strncmp(s1.start, s2.start, s1.len) == 0; ++} ++ ++static inline bool ++svaleq_prefix(struct sval s1, struct sval s2) ++{ ++ return s1.len <= s2.len && strncmp(s1.start, s2.start, s1.len) == 0; ++} ++ ++struct scanner { ++ const char *s; ++ size_t pos; ++ size_t len; ++ char buf[1024]; ++ size_t buf_pos; ++ unsigned line, column; ++ /* The line/column of the start of the current token. */ ++ unsigned token_line, token_column; ++ const char *file_name; ++ struct xkb_context *ctx; ++}; ++ ++#define scanner_log(scanner, level, fmt, ...) \ ++ xkb_log((scanner)->ctx, (level), 0, \ ++ "%s:%u:%u: " fmt "\n", \ ++ (scanner)->file_name, \ ++ (scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__) ++ ++#define scanner_err(scanner, fmt, ...) \ ++ scanner_log(scanner, XKB_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__) ++ ++#define scanner_warn(scanner, fmt, ...) \ ++ scanner_log(scanner, XKB_LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__) ++ ++static inline void ++scanner_init(struct scanner *s, struct xkb_context *ctx, ++ const char *string, size_t len, const char *file_name) ++{ ++ s->s = string; ++ s->len = len; ++ s->pos = 0; ++ s->line = s->column = 1; ++ s->token_line = s->token_column = 1; ++ s->file_name = file_name; ++ s->ctx = ctx; ++} ++ ++static inline char ++peek(struct scanner *s) ++{ ++ if (unlikely(s->pos >= s->len)) ++ return '\0'; ++ return s->s[s->pos]; ++} ++ ++static inline bool ++eof(struct scanner *s) ++{ ++ return s->pos >= s->len; ++} ++ ++static inline bool ++eol(struct scanner *s) ++{ ++ return peek(s) == '\n'; ++} ++ ++static inline char ++next(struct scanner *s) ++{ ++ if (unlikely(eof(s))) ++ return '\0'; ++ if (unlikely(eol(s))) { ++ s->line++; ++ s->column = 1; ++ } ++ else { ++ s->column++; ++ } ++ return s->s[s->pos++]; ++} ++ ++static inline bool ++chr(struct scanner *s, char ch) ++{ ++ if (likely(peek(s) != ch)) ++ return false; ++ s->pos++; s->column++; ++ return true; ++} ++ ++static inline bool ++str(struct scanner *s, const char *string, size_t len) ++{ ++ if (s->len - s->pos < len) ++ return false; ++ if (strncasecmp(s->s + s->pos, string, len) != 0) ++ return false; ++ s->pos += len; s->column += len; ++ return true; ++} ++ ++#define lit(s, literal) str(s, literal, sizeof(literal) - 1) ++ ++static inline bool ++buf_append(struct scanner *s, char ch) ++{ ++ if (s->buf_pos + 1 >= sizeof(s->buf)) ++ return false; ++ s->buf[s->buf_pos++] = ch; ++ return true; ++} ++ ++static inline bool ++oct(struct scanner *s, uint8_t *out) ++{ ++ int i; ++ for (i = 0, *out = 0; peek(s) >= '0' && peek(s) <= '7' && i < 3; i++) ++ *out = *out * 8 + next(s) - '0'; ++ return i > 0; ++} ++ ++#endif +--- a/src/3rdparty/xkbcommon/src/state.c ++++ b/src/3rdparty/xkbcommon/src/state.c +@@ -61,6 +61,7 @@ + + #include "keymap.h" + #include "keysym.h" ++#include "utf8.h" + + struct xkb_filter { + union xkb_action action; +@@ -108,7 +109,7 @@ struct xkb_state { + * < Left Shift down, Right Shift down, Left Shift Up > + * the modifier should still be set. This keeps the count. + */ +- int16_t mod_key_count[sizeof(xkb_mod_mask_t) * 8]; ++ int16_t mod_key_count[XKB_MAX_MODS]; + + int refcnt; + darray(struct xkb_filter) filters; +@@ -121,9 +122,8 @@ get_entry_for_key_state(struct xkb_state + { + const struct xkb_key_type *type = key->groups[group].type; + xkb_mod_mask_t active_mods = state->components.mods & type->mods.mask; +- unsigned int i; + +- for (i = 0; i < type->num_entries; i++) { ++ for (unsigned i = 0; i < type->num_entries; i++) { + /* + * If the virtual modifiers are not bound to anything, we're + * supposed to skip the entry (xserver does this with cached +@@ -170,7 +170,7 @@ wrap_group_into_range(int32_t group, + if (num_groups == 0) + return XKB_LAYOUT_INVALID; + +- if (group < num_groups) ++ if (group >= 0 && (xkb_layout_index_t) group < num_groups) + return group; + + switch (out_of_range_group_action) { +@@ -623,30 +623,42 @@ xkb_state_led_update_all(struct xkb_stat + xkb_mod_mask_t mod_mask = 0; + xkb_layout_mask_t group_mask = 0; + +- if (led->which_mods & XKB_STATE_MODS_EFFECTIVE) +- mod_mask |= state->components.mods; +- if (led->which_mods & XKB_STATE_MODS_DEPRESSED) +- mod_mask |= state->components.base_mods; +- if (led->which_mods & XKB_STATE_MODS_LATCHED) +- mod_mask |= state->components.latched_mods; +- if (led->which_mods & XKB_STATE_MODS_LOCKED) +- mod_mask |= state->components.locked_mods; +- if (led->mods.mask & mod_mask) +- state->components.leds |= (1 << idx); +- +- if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE) +- group_mask |= (1 << state->components.group); +- if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED) +- group_mask |= (1 << state->components.base_group); +- if (led->which_groups & XKB_STATE_LAYOUT_LATCHED) +- group_mask |= (1 << state->components.latched_group); +- if (led->which_groups & XKB_STATE_LAYOUT_LOCKED) +- group_mask |= (1 << state->components.locked_group); +- if (led->groups & group_mask) +- state->components.leds |= (1 << idx); ++ if (led->which_mods != 0 && led->mods.mask != 0) { ++ if (led->which_mods & XKB_STATE_MODS_EFFECTIVE) ++ mod_mask |= state->components.mods; ++ if (led->which_mods & XKB_STATE_MODS_DEPRESSED) ++ mod_mask |= state->components.base_mods; ++ if (led->which_mods & XKB_STATE_MODS_LATCHED) ++ mod_mask |= state->components.latched_mods; ++ if (led->which_mods & XKB_STATE_MODS_LOCKED) ++ mod_mask |= state->components.locked_mods; ++ ++ if (led->mods.mask & mod_mask) { ++ state->components.leds |= (1u << idx); ++ continue; ++ } ++ } ++ ++ if (led->which_groups != 0 && led->groups != 0) { ++ if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE) ++ group_mask |= (1u << state->components.group); ++ if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED) ++ group_mask |= (1u << state->components.base_group); ++ if (led->which_groups & XKB_STATE_LAYOUT_LATCHED) ++ group_mask |= (1u << state->components.latched_group); ++ if (led->which_groups & XKB_STATE_LAYOUT_LOCKED) ++ group_mask |= (1u << state->components.locked_group); ++ ++ if (led->groups & group_mask) { ++ state->components.leds |= (1u << idx); ++ continue; ++ } ++ } + +- if (led->ctrls & state->keymap->enabled_ctrls) +- state->components.leds |= (1 << idx); ++ if (led->ctrls & state->keymap->enabled_ctrls) { ++ state->components.leds |= (1u << idx); ++ continue; ++ } + } + } + +@@ -657,23 +669,27 @@ xkb_state_led_update_all(struct xkb_stat + static void + xkb_state_update_derived(struct xkb_state *state) + { ++ xkb_layout_index_t wrapped; ++ + state->components.mods = (state->components.base_mods | + state->components.latched_mods | + state->components.locked_mods); + + /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */ + ++ wrapped = wrap_group_into_range(state->components.locked_group, ++ state->keymap->num_groups, ++ RANGE_WRAP, 0); + state->components.locked_group = +- wrap_group_into_range(state->components.locked_group, +- state->keymap->num_groups, +- RANGE_WRAP, 0); ++ (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); + ++ wrapped = wrap_group_into_range(state->components.base_group + ++ state->components.latched_group + ++ state->components.locked_group, ++ state->keymap->num_groups, ++ RANGE_WRAP, 0); + state->components.group = +- wrap_group_into_range(state->components.base_group + +- state->components.latched_group + +- state->components.locked_group, +- state->keymap->num_groups, +- RANGE_WRAP, 0); ++ (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); + + xkb_state_led_update_all(state); + } +@@ -781,7 +797,7 @@ xkb_state_update_mask(struct xkb_state * + num_mods = xkb_keymap_num_mods(state->keymap); + + for (idx = 0; idx < num_mods; idx++) { +- xkb_mod_mask_t mod = (1 << idx); ++ xkb_mod_mask_t mod = (1u << idx); + if (base_mods & mod) + state->components.base_mods |= mod; + if (latched_mods & mod) +@@ -826,6 +842,53 @@ err: + return 0; + } + ++/* ++ * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier ++ */ ++static bool ++should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc) ++{ ++ xkb_mod_index_t caps = ++ xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS); ++ ++ return ++ xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 && ++ xkb_state_mod_index_is_consumed(state, kc, caps) == 0; ++} ++ ++/* ++ * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier ++ */ ++static bool ++should_do_ctrl_transformation(struct xkb_state *state, xkb_keycode_t kc) ++{ ++ xkb_mod_index_t ctrl = ++ xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CTRL); ++ ++ return ++ xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0 && ++ xkb_state_mod_index_is_consumed(state, kc, ctrl) == 0; ++} ++ ++/* Verbatim from libX11:src/xkb/XKBBind.c */ ++static char ++XkbToControl(char ch) ++{ ++ char c = ch; ++ ++ if ((c >= '@' && c < '\177') || c == ' ') ++ c &= 0x1F; ++ else if (c == '2') ++ c = '\000'; ++ else if (c >= '3' && c <= '7') ++ c -= ('3' - '\033'); ++ else if (c == '8') ++ c = '\177'; ++ else if (c == '/') ++ c = '_' & 0x1F; ++ return c; ++} ++ + /** + * Provides either exactly one symbol, or XKB_KEY_NoSymbol. + */ +@@ -835,7 +898,6 @@ xkb_state_key_get_one_sym(struct xkb_sta + const xkb_keysym_t *syms; + xkb_keysym_t sym; + int num_syms; +- xkb_mod_index_t caps; + + num_syms = xkb_state_key_get_syms(state, kc, &syms); + if (num_syms != 1) +@@ -843,18 +905,135 @@ xkb_state_key_get_one_sym(struct xkb_sta + + sym = syms[0]; + +- /* +- * Perform capitalization transformation, see: +- * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier +- */ +- caps = xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS); +- if (xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 && +- xkb_state_mod_index_is_consumed(state, kc, caps) == 0) ++ if (should_do_caps_transformation(state, kc)) ++ sym = xkb_keysym_to_upper(sym); ++ ++ return sym; ++} ++ ++/* ++ * The caps and ctrl transformations require some special handling, ++ * so we cannot simply use xkb_state_get_one_sym() for them. ++ * In particular, if Control is set, we must try very hard to find ++ * some layout in which the keysym is ASCII and thus can be (maybe) ++ * converted to a control character. libX11 allows to disable this ++ * behavior with the XkbLC_ControlFallback (see XkbSetXlibControls(3)), ++ * but it is enabled by default, yippee. ++ */ ++static xkb_keysym_t ++get_one_sym_for_string(struct xkb_state *state, xkb_keycode_t kc) ++{ ++ xkb_level_index_t level; ++ xkb_layout_index_t layout, num_layouts; ++ const xkb_keysym_t *syms; ++ int nsyms; ++ xkb_keysym_t sym; ++ ++ layout = xkb_state_key_get_layout(state, kc); ++ num_layouts = xkb_keymap_num_layouts_for_key(state->keymap, kc); ++ level = xkb_state_key_get_level(state, kc, layout); ++ if (layout == XKB_LAYOUT_INVALID || num_layouts == 0 || ++ level == XKB_LEVEL_INVALID) ++ return XKB_KEY_NoSymbol; ++ ++ nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc, ++ layout, level, &syms); ++ if (nsyms != 1) ++ return XKB_KEY_NoSymbol; ++ sym = syms[0]; ++ ++ if (should_do_ctrl_transformation(state, kc) && sym > 127u) { ++ for (xkb_layout_index_t i = 0; i < num_layouts; i++) { ++ level = xkb_state_key_get_level(state, kc, i); ++ if (level == XKB_LEVEL_INVALID) ++ continue; ++ ++ nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc, ++ i, level, &syms); ++ if (nsyms == 1 && syms[0] <= 127u) { ++ sym = syms[0]; ++ break; ++ } ++ } ++ } ++ ++ if (should_do_caps_transformation(state, kc)) { + sym = xkb_keysym_to_upper(sym); ++ } + + return sym; + } + ++XKB_EXPORT int ++xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t kc, ++ char *buffer, size_t size) ++{ ++ xkb_keysym_t sym; ++ const xkb_keysym_t *syms; ++ int nsyms; ++ int offset; ++ char tmp[7]; ++ ++ sym = get_one_sym_for_string(state, kc); ++ if (sym != XKB_KEY_NoSymbol) { ++ nsyms = 1; syms = &sym; ++ } ++ else { ++ nsyms = xkb_state_key_get_syms(state, kc, &syms); ++ } ++ ++ /* Make sure not to truncate in the middle of a UTF-8 sequence. */ ++ offset = 0; ++ for (int i = 0; i < nsyms; i++) { ++ int ret = xkb_keysym_to_utf8(syms[i], tmp, sizeof(tmp)); ++ if (ret <= 0) ++ goto err_bad; ++ ++ ret--; ++ if ((size_t) (offset + ret) <= size) ++ memcpy(buffer + offset, tmp, ret); ++ offset += ret; ++ } ++ ++ if ((size_t) offset >= size) ++ goto err_trunc; ++ buffer[offset] = '\0'; ++ ++ if (!is_valid_utf8(buffer, offset)) ++ goto err_bad; ++ ++ if (offset == 1 && (unsigned int) buffer[0] <= 127u && ++ should_do_ctrl_transformation(state, kc)) ++ buffer[0] = XkbToControl(buffer[0]); ++ ++ return offset; ++ ++err_trunc: ++ if (size > 0) ++ buffer[size - 1] = '\0'; ++ return offset; ++ ++err_bad: ++ if (size > 0) ++ buffer[0] = '\0'; ++ return 0; ++} ++ ++XKB_EXPORT uint32_t ++xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t kc) ++{ ++ xkb_keysym_t sym; ++ uint32_t cp; ++ ++ sym = get_one_sym_for_string(state, kc); ++ cp = xkb_keysym_to_utf32(sym); ++ ++ if (cp <= 127u && should_do_ctrl_transformation(state, kc)) ++ cp = (uint32_t) XkbToControl((char) cp); ++ ++ return cp; ++} ++ + /** + * Serialises the requested modifier state into an xkb_mod_mask_t, with all + * the same disclaimers as in xkb_state_update_mask. +@@ -913,7 +1092,7 @@ xkb_state_mod_index_is_active(struct xkb + if (idx >= xkb_keymap_num_mods(state->keymap)) + return -1; + +- return !!(xkb_state_serialize_mods(state, type) & (1 << idx)); ++ return !!(xkb_state_serialize_mods(state, type) & (1u << idx)); + } + + /** +@@ -964,7 +1143,7 @@ xkb_state_mod_indices_are_active(struct + ret = -1; + break; + } +- wanted |= (1 << idx); ++ wanted |= (1u << idx); + } + va_end(ap); + +@@ -1015,7 +1194,7 @@ xkb_state_mod_names_are_active(struct xk + ret = -1; + break; + } +- wanted |= (1 << idx); ++ wanted |= (1u << idx); + } + va_end(ap); + +@@ -1042,11 +1221,11 @@ xkb_state_layout_index_is_active(struct + if (type & XKB_STATE_LAYOUT_EFFECTIVE) + ret |= (state->components.group == idx); + if (type & XKB_STATE_LAYOUT_DEPRESSED) +- ret |= (state->components.base_group == idx); ++ ret |= (state->components.base_group == (int32_t) idx); + if (type & XKB_STATE_LAYOUT_LATCHED) +- ret |= (state->components.latched_group == idx); ++ ret |= (state->components.latched_group == (int32_t) idx); + if (type & XKB_STATE_LAYOUT_LOCKED) +- ret |= (state->components.locked_group == idx); ++ ret |= (state->components.locked_group == (int32_t) idx); + + return ret; + } +@@ -1077,7 +1256,7 @@ xkb_state_led_index_is_active(struct xkb + darray_item(state->keymap->leds, idx).name == XKB_ATOM_NONE) + return -1; + +- return !!(state->components.leds & (1 << idx)); ++ return !!(state->components.leds & (1u << idx)); + } + + /** +@@ -1097,18 +1276,24 @@ xkb_state_led_name_is_active(struct xkb_ + static xkb_mod_mask_t + key_get_consumed(struct xkb_state *state, const struct xkb_key *key) + { ++ const struct xkb_key_type *type; + const struct xkb_key_type_entry *entry; ++ xkb_mod_mask_t preserve; + xkb_layout_index_t group; + + group = xkb_state_key_get_layout(state, key->keycode); + if (group == XKB_LAYOUT_INVALID) + return 0; + ++ type = key->groups[group].type; ++ + entry = get_entry_for_key_state(state, key, group); +- if (!entry) +- return 0; ++ if (entry) ++ preserve = entry->preserve.mask; ++ else ++ preserve = 0; + +- return entry->mods.mask & ~entry->preserve.mask; ++ return type->mods.mask & ~preserve; + } + + /** +@@ -1132,7 +1317,7 @@ xkb_state_mod_index_is_consumed(struct x + if (!key || idx >= xkb_keymap_num_mods(state->keymap)) + return -1; + +- return !!((1 << idx) & key_get_consumed(state, key)); ++ return !!((1u << idx) & key_get_consumed(state, key)); + } + + /** +@@ -1154,3 +1339,14 @@ xkb_state_mod_mask_remove_consumed(struc + + return mask & ~key_get_consumed(state, key); + } ++ ++XKB_EXPORT xkb_mod_mask_t ++xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc) ++{ ++ const struct xkb_key *key = XkbKey(state->keymap, kc); ++ ++ if (!key) ++ return 0; ++ ++ return key_get_consumed(state, key); ++} +--- a/src/3rdparty/xkbcommon/src/text.c ++++ b/src/3rdparty/xkbcommon/src/text.c +@@ -280,7 +280,7 @@ ModMaskText(const struct xkb_keymap *key + darray_enumerate(i, mod, keymap->mods) { + int ret; + +- if (!(mask & (1 << i))) ++ if (!(mask & (1u << i))) + continue; + + ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s", +@@ -307,14 +307,14 @@ LedStateMaskText(struct xkb_context *ctx + for (unsigned i = 0; mask; i++) { + int ret; + +- if (!(mask & (1 << i))) ++ if (!(mask & (1u << i))) + continue; + +- mask &= ~(1 << i); ++ mask &= ~(1u << i); + + ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s", + pos == 0 ? "" : "+", +- LookupValue(modComponentMaskNames, 1 << i)); ++ LookupValue(modComponentMaskNames, 1u << i)); + if (ret <= 0 || pos + ret >= sizeof(buf)) + break; + else +@@ -339,14 +339,14 @@ ControlMaskText(struct xkb_context *ctx, + for (unsigned i = 0; mask; i++) { + int ret; + +- if (!(mask & (1 << i))) ++ if (!(mask & (1u << i))) + continue; + +- mask &= ~(1 << i); ++ mask &= ~(1u << i); + + ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s", + pos == 0 ? "" : "+", +- LookupValue(ctrlMaskNames, 1 << i)); ++ LookupValue(ctrlMaskNames, 1u << i)); + if (ret <= 0 || pos + ret >= sizeof(buf)) + break; + else +--- /dev/null ++++ b/src/3rdparty/xkbcommon/src/utf8.c +@@ -0,0 +1,142 @@ ++/* ++ * Copyright © 2012 Intel Corporation ++ * Copyright © 2014 Ran Benita ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Author: Rob Bradford ++ */ ++ ++#include ++#include ++#include ++ ++#include "utf8.h" ++ ++int ++utf32_to_utf8(uint32_t unichar, char *buffer) ++{ ++ int count, shift, length; ++ uint8_t head; ++ ++ if (unichar <= 0x007f) { ++ buffer[0] = unichar; ++ buffer[1] = '\0'; ++ return 2; ++ } ++ else if (unichar <= 0x07FF) { ++ length = 2; ++ head = 0xc0; ++ } ++ else if (unichar <= 0xffff) { ++ length = 3; ++ head = 0xe0; ++ } ++ else if (unichar <= 0x1fffff) { ++ length = 4; ++ head = 0xf0; ++ } ++ else if (unichar <= 0x3ffffff) { ++ length = 5; ++ head = 0xf8; ++ } ++ else { ++ length = 6; ++ head = 0xfc; ++ } ++ ++ for (count = length - 1, shift = 0; count > 0; count--, shift += 6) ++ buffer[count] = 0x80 | ((unichar >> shift) & 0x3f); ++ ++ buffer[0] = head | ((unichar >> shift) & 0x3f); ++ buffer[length] = '\0'; ++ ++ return length + 1; ++} ++ ++bool ++is_valid_utf8(const char *ss, size_t len) ++{ ++ size_t i = 0; ++ size_t tail_bytes = 0; ++ const uint8_t *s = (const uint8_t *) ss; ++ ++ /* This beauty is from: ++ * The Unicode Standard Version 6.2 - Core Specification, Table 3.7 ++ * http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G7404 ++ * We can optimize if needed. */ ++ while (i < len) ++ { ++ if (s[i] <= 0x7F) { ++ tail_bytes = 0; ++ } ++ else if (s[i] >= 0xC2 && s[i] <= 0xDF) { ++ tail_bytes = 1; ++ } ++ else if (s[i] == 0xE0) { ++ i++; ++ if (i >= len || !(s[i] >= 0xA0 && s[i] <= 0xBF)) ++ return false; ++ tail_bytes = 1; ++ } ++ else if (s[i] >= 0xE1 && s[i] <= 0xEC) { ++ tail_bytes = 2; ++ } ++ else if (s[i] == 0xED) { ++ i++; ++ if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x9F)) ++ return false; ++ tail_bytes = 1; ++ } ++ else if (s[i] >= 0xEE && s[i] <= 0xEF) { ++ tail_bytes = 2; ++ } ++ else if (s[i] == 0xF0) { ++ i++; ++ if (i >= len || !(s[i] >= 0x90 && s[i] <= 0xBF)) ++ return false; ++ tail_bytes = 2; ++ } ++ else if (s[i] >= 0xF1 && s[i] <= 0xF3) { ++ tail_bytes = 3; ++ } ++ else if (s[i] == 0xF4) { ++ i++; ++ if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x8F)) ++ return false; ++ tail_bytes = 2; ++ } ++ else { ++ return false; ++ } ++ ++ i++; ++ ++ while (i < len && tail_bytes > 0 && s[i] >= 0x80 && s[i] <= 0xBF) { ++ i++; ++ tail_bytes--; ++ } ++ ++ if (tail_bytes != 0) ++ return false; ++ } ++ ++ return true; ++} +--- /dev/null ++++ b/src/3rdparty/xkbcommon/src/utf8.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright © 2012 Intel Corporation ++ * Copyright © 2014 Ran Benita ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Author: Rob Bradford ++ */ ++ ++#ifndef XKBCOMMON_UTF8_H ++#define XKBCOMMON_UTF8_H ++ ++int ++utf32_to_utf8(uint32_t unichar, char *buffer); ++ ++bool ++is_valid_utf8(const char *ss, size_t len); ++ ++#endif +--- a/src/3rdparty/xkbcommon/src/utils.h ++++ b/src/3rdparty/xkbcommon/src/utils.h +@@ -163,13 +163,13 @@ is_graph(char ch) + * Note: this is 1-based! It's more useful this way, and returns 0 when + * mask is all 0s. + */ +-static inline int ++static inline unsigned + msb_pos(uint32_t mask) + { +- int pos = 0; ++ unsigned pos = 0; + while (mask) { + pos++; +- mask >>= 1; ++ mask >>= 1u; + } + return pos; + } +@@ -187,6 +187,22 @@ unmap_file(const char *str, size_t size) + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + #define MAX3(a, b, c) MAX(MAX((a), (b)), (c)) + ++#if defined(HAVE_SECURE_GETENV) ++# define secure_getenv secure_getenv ++#elif defined(HAVE___SECURE_GETENV) ++# define secure_getenv __secure_getenv ++#else ++# define secure_getenv getenv ++#endif ++ ++#if defined(HAVE___BUILTIN_EXPECT) ++# define likely(x) __builtin_expect(!!(x), 1) ++# define unlikely(x) __builtin_expect(!!(x), 0) ++#else ++# define likely(x) (x) ++# define unlikely(x) (x) ++#endif ++ + /* Compiler Attributes */ + + #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__CYGWIN__) +--- a/src/3rdparty/xkbcommon/src/x11/x11-keymap.c ++++ b/src/3rdparty/xkbcommon/src/x11/x11-keymap.c +@@ -43,13 +43,13 @@ + + /* Constants from /usr/include/X11/extensions/XKB.h */ + /* XkbNumModifiers. */ +-#define NUM_REAL_MODS 8 ++#define NUM_REAL_MODS 8u + /* XkbNumVirtualMods. */ +-#define NUM_VMODS 16 ++#define NUM_VMODS 16u + /* XkbNoModifier. */ + #define NO_MODIFIER 0xff + /* XkbNumIndicators. */ +-#define NUM_INDICATORS 32 ++#define NUM_INDICATORS 32u + /* XkbAllIndicatorsMask. */ + #define ALL_INDICATORS_MASK 0xffffffff + +@@ -92,11 +92,14 @@ translate_mods(uint8_t rmods, uint16_t v + { + /* We represent mod masks in a single uint32_t value, with real mods + * first and vmods after (though we don't make these distinctions). */ +- return rmods | (vmods_low << 8) | (vmods_high << 16); ++ return ++ ((xkb_mod_mask_t) rmods) | ++ ((xkb_mod_mask_t) vmods_low << 8) | ++ ((xkb_mod_mask_t) vmods_high << 16); + } + + static enum xkb_action_controls +-translate_controls_mask(uint16_t wire) ++translate_controls_mask(uint32_t wire) + { + enum xkb_action_controls ret = 0; + if (wire & XCB_XKB_BOOL_CTRL_REPEAT_KEYS) +@@ -218,8 +221,8 @@ translate_action(union xkb_action *actio + action->ptr.x = (wire->moveptr.xLow | (wire->moveptr.xHigh << 8)); + action->ptr.y = (wire->moveptr.yLow | (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) +@@ -263,7 +266,7 @@ translate_action(union xkb_action *actio + + 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; +@@ -351,7 +354,7 @@ get_types(struct xkb_keymap *keymap, xcb + xcb_xkb_mod_def_iterator_t preserves_iter = + xcb_xkb_key_type_preserve_iterator(wire_type); + +- FAIL_UNLESS(preserves_length <= type->num_entries); ++ FAIL_UNLESS((unsigned) preserves_length <= type->num_entries); + + for (int j = 0; j < preserves_length; j++) { + xcb_xkb_mod_def_t *wire_preserve = preserves_iter.data; +@@ -402,7 +405,7 @@ get_sym_maps(struct xkb_keymap *keymap, + FAIL_UNLESS(key->num_groups <= ARRAY_SIZE(wire_sym_map->kt_index)); + ALLOC_OR_FAIL(key->groups, key->num_groups); + +- for (int j = 0; j < key->num_groups; j++) { ++ for (unsigned j = 0; j < key->num_groups; j++) { + FAIL_UNLESS(wire_sym_map->kt_index[j] < keymap->num_types); + key->groups[j].type = &keymap->types[wire_sym_map->kt_index[j]]; + +@@ -424,7 +427,7 @@ get_sym_maps(struct xkb_keymap *keymap, + int syms_length = xcb_xkb_key_sym_map_syms_length(wire_sym_map); + xcb_keysym_t *syms_iter = xcb_xkb_key_sym_map_syms(wire_sym_map); + +- FAIL_UNLESS(syms_length == wire_sym_map->width * key->num_groups); ++ 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; +@@ -468,9 +471,12 @@ get_actions(struct xkb_keymap *keymap, x + + for (int i = 0; i < acts_count_length; i++) { + xcb_xkb_key_sym_map_t *wire_sym_map = sym_maps_iter.data; ++ int syms_length = xcb_xkb_key_sym_map_syms_length(wire_sym_map); + uint8_t wire_count = *acts_count_iter; + struct xkb_key *key = &keymap->keys[reply->firstKeyAction + i]; + ++ 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; +@@ -505,8 +511,8 @@ get_vmods(struct xkb_keymap *keymap, xcb + darray_resize0(keymap->mods, + NUM_REAL_MODS + msb_pos(reply->virtualMods)); + +- for (int i = 0; i < NUM_VMODS; i++) { +- if (reply->virtualMods & (1 << i)) { ++ 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); + +@@ -530,11 +536,13 @@ get_explicits(struct xkb_keymap *keymap, + + 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; +@@ -573,11 +581,12 @@ get_modmaps(struct xkb_keymap *keymap, x + + 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); +@@ -599,11 +608,12 @@ get_vmodmaps(struct xkb_keymap *keymap, + + 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); +@@ -677,8 +687,8 @@ get_indicators(struct xkb_keymap *keymap + + darray_resize0(keymap->leds, msb_pos(reply->which)); + +- for (int i = 0; i < NUM_INDICATORS; i++) { +- if (reply->which & (1 << i)) { ++ 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); + +@@ -879,8 +889,8 @@ get_indicator_names(struct xkb_keymap *k + + FAIL_UNLESS(msb_pos(reply->indicators) <= darray_size(keymap->leds)); + +- for (int i = 0; i < NUM_INDICATORS; i++) { +- if (reply->indicators & (1 << i)) { ++ 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); + +@@ -911,8 +921,8 @@ get_vmod_names(struct xkb_keymap *keymap + */ + darray_resize0(keymap->mods, NUM_REAL_MODS + msb_pos(reply->virtualMods)); + +- for (int i = 0; i < NUM_VMODS; i++) { +- if (reply->virtualMods & (1 << i)) { ++ 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); + +@@ -959,7 +969,7 @@ get_key_names(struct xkb_keymap *keymap, + FAIL_UNLESS(reply->minKeyCode == keymap->min_key_code); + FAIL_UNLESS(reply->maxKeyCode == keymap->max_key_code); + FAIL_UNLESS(reply->firstKey == keymap->min_key_code); +- FAIL_UNLESS(reply->firstKey + reply->nKeys - 1 == keymap->max_key_code); ++ FAIL_UNLESS(reply->firstKey + reply->nKeys - 1U == keymap->max_key_code); + + for (int i = 0; i < length; i++) { + xcb_xkb_key_name_t *wire = iter.data; +@@ -1023,7 +1033,7 @@ static bool + get_names(struct xkb_keymap *keymap, xcb_connection_t *conn, + uint16_t device_id) + { +- static const xcb_xkb_name_detail_t required_names = ++ static const xcb_xkb_name_detail_t wanted = + (XCB_XKB_NAME_DETAIL_KEYCODES | + XCB_XKB_NAME_DETAIL_SYMBOLS | + XCB_XKB_NAME_DETAIL_TYPES | +@@ -1035,17 +1045,21 @@ get_names(struct xkb_keymap *keymap, xcb + 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 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); + + xcb_xkb_get_names_cookie_t cookie = +- xcb_xkb_get_names(conn, device_id, required_names); ++ xcb_xkb_get_names(conn, device_id, wanted); + 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 & required) == required); + + xcb_xkb_get_names_value_list_unpack(xcb_xkb_get_names_value_list(reply), + reply->nTypes, +@@ -1093,13 +1107,14 @@ get_controls(struct xkb_keymap *keymap, + 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; + + FAIL_UNLESS(keymap->max_key_code < XCB_XKB_CONST_PER_KEY_BIT_ARRAY_SIZE * 8); + +- for (int i = keymap->min_key_code; i <= keymap->max_key_code; i++) ++ 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))); + + free(reply); +@@ -1119,7 +1134,7 @@ xkb_x11_keymap_new_from_device(struct xk + struct xkb_keymap *keymap; + const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1; + +- if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) { ++ if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } +--- a/src/3rdparty/xkbcommon/src/x11/x11-priv.h ++++ b/src/3rdparty/xkbcommon/src/x11/x11-priv.h +@@ -26,8 +26,8 @@ + + #include + +-#include "xkbcommon/xkbcommon-x11.h" + #include "keymap.h" ++#include "xkbcommon/xkbcommon-x11.h" + + /* Get a strdup'd name of an X atom. */ + bool +--- a/src/3rdparty/xkbcommon/src/xkb-keymap.c ++++ b/src/3rdparty/xkbcommon/src/xkb-keymap.c +@@ -110,10 +110,10 @@ get_keymap_format_ops(enum xkb_keymap_fo + [XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops, + }; + +- if ((int) format < 0 || (int) format >= ARRAY_SIZE(keymap_format_ops)) ++ if ((int) format < 0 || (int) format >= (int) ARRAY_SIZE(keymap_format_ops)) + return NULL; + +- return keymap_format_ops[format]; ++ return keymap_format_ops[(int) format]; + } + + XKB_EXPORT struct xkb_keymap * +@@ -132,33 +132,20 @@ xkb_keymap_new_from_names(struct xkb_con + return NULL; + } + +- if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) { ++ if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } + ++ keymap = xkb_keymap_new(ctx, format, flags); ++ if (!keymap) ++ return NULL; ++ + if (rmlvo_in) + rmlvo = *rmlvo_in; + else + memset(&rmlvo, 0, sizeof(rmlvo)); +- +- if (isempty(rmlvo.rules)) +- rmlvo.rules = xkb_context_get_default_rules(ctx); +- if (isempty(rmlvo.model)) +- rmlvo.model = xkb_context_get_default_model(ctx); +- /* Layout and variant are tied together, so don't try to use one from +- * the caller and one from the environment. */ +- if (isempty(rmlvo.layout)) { +- rmlvo.layout = xkb_context_get_default_layout(ctx); +- rmlvo.variant = xkb_context_get_default_variant(ctx); +- } +- /* Options can be empty, so respect that if passed in. */ +- if (rmlvo.options == NULL) +- rmlvo.options = xkb_context_get_default_options(ctx); +- +- keymap = xkb_keymap_new(ctx, format, flags); +- if (!keymap) +- return NULL; ++ xkb_context_sanitize_rule_names(ctx, &rmlvo); + + if (!ops->keymap_new_from_names(keymap, &rmlvo)) { + xkb_keymap_unref(keymap); +@@ -193,7 +180,7 @@ xkb_keymap_new_from_buffer(struct xkb_co + return NULL; + } + +- if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) { ++ if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } +@@ -230,7 +217,7 @@ xkb_keymap_new_from_file(struct xkb_cont + return NULL; + } + +- if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) { ++ if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } +--- a/src/3rdparty/xkbcommon/src/xkbcomp/action.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/action.c +@@ -118,6 +118,8 @@ NewActionsInfo(void) + /* Increment default button. */ + info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.flags = 0; + info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.value = 1; ++ info->actions[ACTION_TYPE_PTR_MOVE].ptr.flags = ACTION_ACCEL; ++ info->actions[ACTION_TYPE_SWITCH_VT].screen.flags = ACTION_SAME_SCREEN; + + return info; + } +@@ -186,10 +188,10 @@ fieldText(enum action_field field) + /***====================================================================***/ + + static inline bool +-ReportMismatch(struct xkb_keymap *keymap, enum xkb_action_type action, ++ReportMismatch(struct xkb_context *ctx, enum xkb_action_type action, + enum action_field field, const char *type) + { +- log_err(keymap->ctx, ++ log_err(ctx, + "Value of %s field must be of type %s; " + "Action %s definition ignored\n", + fieldText(field), type, ActionTypeText(action)); +@@ -197,10 +199,10 @@ ReportMismatch(struct xkb_keymap *keymap + } + + static inline bool +-ReportIllegal(struct xkb_keymap *keymap, enum xkb_action_type action, ++ReportIllegal(struct xkb_context *ctx, enum xkb_action_type action, + enum action_field field) + { +- log_err(keymap->ctx, ++ log_err(ctx, + "Field %s is not defined for an action of type %s; " + "Action definition ignored\n", + fieldText(field), ActionTypeText(action)); +@@ -208,10 +210,10 @@ ReportIllegal(struct xkb_keymap *keymap, + } + + static inline bool +-ReportActionNotArray(struct xkb_keymap *keymap, enum xkb_action_type action, ++ReportActionNotArray(struct xkb_context *ctx, enum xkb_action_type action, + enum action_field field) + { +- log_err(keymap->ctx, ++ log_err(ctx, + "The %s field in the %s action is not an array; " + "Action definition ignored\n", + fieldText(field), ActionTypeText(action)); +@@ -228,42 +230,40 @@ HandleNoAction(struct xkb_keymap *keymap + } + + static bool +-CheckLatchLockFlags(struct xkb_keymap *keymap, enum xkb_action_type action, +- enum action_field field, const ExprDef *value, +- enum xkb_action_flags *flags_inout) +-{ +- enum xkb_action_flags tmp; +- bool result; +- +- if (field == ACTION_FIELD_CLEAR_LOCKS) +- tmp = ACTION_LOCK_CLEAR; +- else if (field == ACTION_FIELD_LATCH_TO_LOCK) +- tmp = ACTION_LATCH_TO_LOCK; +- else +- return false; /* WSGO! */ ++CheckBooleanFlag(struct xkb_context *ctx, enum xkb_action_type action, ++ enum action_field field, enum xkb_action_flags flag, ++ const ExprDef *array_ndx, const ExprDef *value, ++ enum xkb_action_flags *flags_inout) ++{ ++ bool set; + +- if (!ExprResolveBoolean(keymap->ctx, value, &result)) +- return ReportMismatch(keymap, action, field, "boolean"); ++ if (array_ndx) ++ return ReportActionNotArray(ctx, action, field); + +- if (result) +- *flags_inout |= tmp; ++ if (!ExprResolveBoolean(ctx, value, &set)) ++ return ReportMismatch(ctx, action, field, "boolean"); ++ ++ if (set) ++ *flags_inout |= flag; + else +- *flags_inout &= ~tmp; ++ *flags_inout &= ~flag; + + return true; + } + + static bool + CheckModifierField(struct xkb_keymap *keymap, enum xkb_action_type action, +- const ExprDef *value, enum xkb_action_flags *flags_inout, +- xkb_mod_mask_t *mods_rtrn) ++ const ExprDef *array_ndx, const ExprDef *value, ++ enum xkb_action_flags *flags_inout, xkb_mod_mask_t *mods_rtrn) + { ++ if (array_ndx) ++ return ReportActionNotArray(keymap->ctx, action, ACTION_FIELD_MODIFIERS); ++ + if (value->expr.op == EXPR_IDENT) { + const char *valStr; + valStr = xkb_atom_text(keymap->ctx, value->ident.ident); + if (valStr && (istreq(valStr, "usemodmapmods") || + istreq(valStr, "modmapmods"))) { +- + *mods_rtrn = 0; + *flags_inout |= ACTION_MODS_LOOKUP_MODMAP; + return true; +@@ -271,184 +271,130 @@ CheckModifierField(struct xkb_keymap *ke + } + + if (!ExprResolveModMask(keymap, value, MOD_BOTH, mods_rtrn)) +- return ReportMismatch(keymap, action, ++ return ReportMismatch(keymap->ctx, action, + ACTION_FIELD_MODIFIERS, "modifier mask"); + + *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP; + return true; + } + ++static const LookupEntry lockWhich[] = { ++ { "both", 0 }, ++ { "lock", ACTION_LOCK_NO_UNLOCK }, ++ { "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) }, ++ { "unlock", ACTION_LOCK_NO_LOCK }, ++ { NULL, 0 } ++}; ++ + static bool +-HandleSetLatchMods(struct xkb_keymap *keymap, union xkb_action *action, +- enum action_field field, const ExprDef *array_ndx, +- const ExprDef *value) ++CheckAffectField(struct xkb_context *ctx, enum xkb_action_type action, ++ const ExprDef *array_ndx, const ExprDef *value, ++ enum xkb_action_flags *flags_inout) + { +- struct xkb_mod_action *act = &action->mods; +- enum xkb_action_flags rtrn, t1; +- xkb_mod_mask_t t2; ++ enum xkb_action_flags flags; + +- if (array_ndx != NULL) { +- switch (field) { +- case ACTION_FIELD_CLEAR_LOCKS: +- case ACTION_FIELD_LATCH_TO_LOCK: +- case ACTION_FIELD_MODIFIERS: +- return ReportActionNotArray(keymap, action->type, field); +- default: +- break; +- } +- } +- +- switch (field) { +- case ACTION_FIELD_CLEAR_LOCKS: +- case ACTION_FIELD_LATCH_TO_LOCK: +- rtrn = act->flags; +- if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) { +- act->flags = rtrn; +- return true; +- } +- return false; +- +- case ACTION_FIELD_MODIFIERS: +- t1 = act->flags; +- if (CheckModifierField(keymap, action->type, value, &t1, &t2)) { +- act->flags = t1; +- act->mods.mods = t2; +- return true; +- } +- return false; ++ if (array_ndx) ++ return ReportActionNotArray(ctx, action, ACTION_FIELD_AFFECT); + +- default: +- break; +- } ++ if (!ExprResolveEnum(ctx, value, &flags, lockWhich)) ++ return ReportMismatch(ctx, action, ACTION_FIELD_AFFECT, ++ "lock, unlock, both, neither"); + +- return ReportIllegal(keymap, action->type, field); ++ *flags_inout &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK); ++ *flags_inout |= flags; ++ return true; + } + + static bool +-HandleLockMods(struct xkb_keymap *keymap, union xkb_action *action, +- enum action_field field, const ExprDef *array_ndx, +- const ExprDef *value) ++HandleSetLatchLockMods(struct xkb_keymap *keymap, union xkb_action *action, ++ enum action_field field, const ExprDef *array_ndx, ++ const ExprDef *value) + { + struct xkb_mod_action *act = &action->mods; +- enum xkb_action_flags t1; +- xkb_mod_mask_t t2; ++ const enum xkb_action_type type = action->type; + +- if (array_ndx && field == ACTION_FIELD_MODIFIERS) +- return ReportActionNotArray(keymap, action->type, field); +- +- switch (field) { +- case ACTION_FIELD_MODIFIERS: +- t1 = act->flags; +- if (CheckModifierField(keymap, action->type, value, &t1, &t2)) { +- act->flags = t1; +- act->mods.mods = t2; +- return true; +- } +- return false; +- +- default: +- break; +- } +- +- return ReportIllegal(keymap, action->type, field); ++ if (field == ACTION_FIELD_MODIFIERS) ++ return CheckModifierField(keymap, action->type, array_ndx, value, ++ &act->flags, &act->mods.mods); ++ if ((type == ACTION_TYPE_MOD_SET || type == ACTION_TYPE_MOD_LATCH) && ++ field == ACTION_FIELD_CLEAR_LOCKS) ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_LOCK_CLEAR, array_ndx, value, ++ &act->flags); ++ if (type == ACTION_TYPE_MOD_LATCH && ++ field == ACTION_FIELD_LATCH_TO_LOCK) ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_LATCH_TO_LOCK, array_ndx, value, ++ &act->flags); ++ if (type == ACTION_TYPE_MOD_LOCK && ++ field == ACTION_FIELD_AFFECT) ++ return CheckAffectField(keymap->ctx, action->type, array_ndx, value, ++ &act->flags); ++ ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static bool +-CheckGroupField(struct xkb_keymap *keymap, unsigned action, +- const ExprDef *value, enum xkb_action_flags *flags_inout, +- xkb_layout_index_t *grp_rtrn) ++CheckGroupField(struct xkb_context *ctx, unsigned action, ++ const ExprDef *array_ndx, const ExprDef *value, ++ enum xkb_action_flags *flags_inout, int32_t *group_rtrn) + { + const ExprDef *spec; ++ xkb_layout_index_t idx; ++ enum xkb_action_flags flags = *flags_inout; ++ ++ if (array_ndx) ++ return ReportActionNotArray(ctx, action, ACTION_FIELD_GROUP); + + if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) { +- *flags_inout &= ~ACTION_ABSOLUTE_SWITCH; ++ flags &= ~ACTION_ABSOLUTE_SWITCH; + spec = value->unary.child; + } + else { +- *flags_inout |= ACTION_ABSOLUTE_SWITCH; ++ flags |= ACTION_ABSOLUTE_SWITCH; + spec = value; + } + +- if (!ExprResolveGroup(keymap->ctx, spec, grp_rtrn)) +- return ReportMismatch(keymap, action, ACTION_FIELD_GROUP, ++ if (!ExprResolveGroup(ctx, spec, &idx)) ++ return ReportMismatch(ctx, action, ACTION_FIELD_GROUP, + "integer (range 1..8)"); + +- if (value->expr.op == EXPR_NEGATE) +- *grp_rtrn = -*grp_rtrn; +- else if (value->expr.op != EXPR_UNARY_PLUS) +- (*grp_rtrn)--; +- +- return true; +-} +- +-static bool +-HandleSetLatchGroup(struct xkb_keymap *keymap, union xkb_action *action, +- enum action_field field, const ExprDef *array_ndx, +- const ExprDef *value) +-{ +- struct xkb_group_action *act = &action->group; +- enum xkb_action_flags rtrn, t1; +- xkb_layout_index_t t2; +- +- if (array_ndx != NULL) { +- switch (field) { +- case ACTION_FIELD_CLEAR_LOCKS: +- case ACTION_FIELD_LATCH_TO_LOCK: +- case ACTION_FIELD_GROUP: +- return ReportActionNotArray(keymap, action->type, field); +- +- default: +- break; +- } ++ /* +n, -n are relative, n is absolute. */ ++ if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) { ++ *group_rtrn = (int32_t) idx; ++ if (value->expr.op == EXPR_NEGATE) ++ *group_rtrn = -*group_rtrn; + } +- +- switch (field) { +- case ACTION_FIELD_CLEAR_LOCKS: +- case ACTION_FIELD_LATCH_TO_LOCK: +- rtrn = act->flags; +- if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) { +- act->flags = rtrn; +- return true; +- } +- return false; +- +- case ACTION_FIELD_GROUP: +- t1 = act->flags; +- if (CheckGroupField(keymap, action->type, value, &t1, &t2)) { +- act->flags = t1; +- act->group = t2; +- return true; +- } +- return false; +- +- default: +- break; ++ else { ++ *group_rtrn = (int32_t) (idx - 1); + } +- +- return ReportIllegal(keymap, action->type, field); ++ *flags_inout = flags; ++ return true; + } + + static bool +-HandleLockGroup(struct xkb_keymap *keymap, union xkb_action *action, +- enum action_field field, const ExprDef *array_ndx, +- const ExprDef *value) ++HandleSetLatchLockGroup(struct xkb_keymap *keymap, union xkb_action *action, ++ enum action_field field, const ExprDef *array_ndx, ++ const ExprDef *value) + { + struct xkb_group_action *act = &action->group; +- enum xkb_action_flags t1; +- xkb_layout_index_t t2; ++ const enum xkb_action_type type = action->type; + +- if ((array_ndx != NULL) && (field == ACTION_FIELD_GROUP)) +- return ReportActionNotArray(keymap, action->type, field); +- if (field == ACTION_FIELD_GROUP) { +- t1 = act->flags; +- if (CheckGroupField(keymap, action->type, value, &t1, &t2)) { +- act->flags = t1; +- act->group = t2; +- return true; +- } +- return false; +- } +- return ReportIllegal(keymap, action->type, field); ++ if (field == ACTION_FIELD_GROUP) ++ return CheckGroupField(keymap->ctx, action->type, array_ndx, value, ++ &act->flags, &act->group); ++ if ((type == ACTION_TYPE_GROUP_SET || type == ACTION_TYPE_GROUP_LATCH) && ++ field == ACTION_FIELD_CLEAR_LOCKS) ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_LOCK_CLEAR, array_ndx, value, ++ &act->flags); ++ if (type == ACTION_TYPE_GROUP_LATCH && ++ field == ACTION_FIELD_LATCH_TO_LOCK) ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_LATCH_TO_LOCK, array_ndx, value, ++ &act->flags); ++ ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static bool +@@ -458,53 +404,47 @@ HandleMovePtr(struct xkb_keymap *keymap, + { + struct xkb_pointer_action *act = &action->ptr; + +- if (array_ndx && (field == ACTION_FIELD_X || field == ACTION_FIELD_Y)) +- return ReportActionNotArray(keymap, action->type, field); +- + if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) { + int val; + const bool absolute = (value->expr.op != EXPR_NEGATE && + value->expr.op != EXPR_UNARY_PLUS); + ++ if (array_ndx) ++ return ReportActionNotArray(keymap->ctx, action->type, field); ++ + if (!ExprResolveInteger(keymap->ctx, value, &val)) +- return ReportMismatch(keymap, action->type, field, "integer"); ++ return ReportMismatch(keymap->ctx, action->type, field, "integer"); ++ ++ if (val < INT16_MIN || val > INT16_MAX) { ++ log_err(keymap->ctx, ++ "The %s field in the %s action must be in range %d..%d; " ++ "Action definition ignored\n", ++ fieldText(field), ActionTypeText(action->type), ++ INT16_MIN, INT16_MAX); ++ return false; ++ } + + if (field == ACTION_FIELD_X) { + if (absolute) + act->flags |= ACTION_ABSOLUTE_X; +- act->x = val; ++ act->x = (int16_t) val; + } + else { + if (absolute) + act->flags |= ACTION_ABSOLUTE_Y; +- act->y = val; ++ act->y = (int16_t) val; + } + + return true; + } + else if (field == ACTION_FIELD_ACCEL) { +- bool set; +- +- if (!ExprResolveBoolean(keymap->ctx, value, &set)) +- return ReportMismatch(keymap, action->type, field, "boolean"); +- +- if (set) +- act->flags &= ~ACTION_NO_ACCEL; +- else +- act->flags |= ACTION_NO_ACCEL; ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_ACCEL, array_ndx, value, &act->flags); + } + +- return ReportIllegal(keymap, action->type, field); ++ return ReportIllegal(keymap->ctx, action->type, field); + } + +-static const LookupEntry lockWhich[] = { +- { "both", 0 }, +- { "lock", ACTION_LOCK_NO_UNLOCK }, +- { "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) }, +- { "unlock", ACTION_LOCK_NO_LOCK }, +- { NULL, 0 } +-}; +- + static bool + HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action, + enum action_field field, const ExprDef *array_ndx, +@@ -516,10 +456,10 @@ HandlePtrBtn(struct xkb_keymap *keymap, + int btn; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + + if (!ExprResolveButton(keymap->ctx, value, &btn)) +- return ReportMismatch(keymap, action->type, field, ++ return ReportMismatch(keymap->ctx, action->type, field, + "integer (range 1..5)"); + + if (btn < 0 || btn > 5) { +@@ -534,40 +474,30 @@ HandlePtrBtn(struct xkb_keymap *keymap, + } + else if (action->type == ACTION_TYPE_PTR_LOCK && + field == ACTION_FIELD_AFFECT) { +- enum xkb_action_flags val; +- +- if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); +- +- if (!ExprResolveEnum(keymap->ctx, value, &val, lockWhich)) +- return ReportMismatch(keymap, action->type, field, +- "lock or unlock"); +- +- act->flags &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK); +- act->flags |= val; +- return true; ++ return CheckAffectField(keymap->ctx, action->type, array_ndx, value, ++ &act->flags); + } + else if (field == ACTION_FIELD_COUNT) { +- int btn; ++ int val; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + +- /* XXX: Should this actually be ResolveButton? */ +- if (!ExprResolveButton(keymap->ctx, value, &btn)) +- return ReportMismatch(keymap, action->type, field, "integer"); ++ if (!ExprResolveInteger(keymap->ctx, value, &val)) ++ return ReportMismatch(keymap->ctx, action->type, field, "integer"); + +- if (btn < 0 || btn > 255) { ++ if (val < 0 || val > 255) { + log_err(keymap->ctx, + "The count field must have a value in the range 0..255; " +- "Illegal count %d ignored\n", btn); ++ "Illegal count %d ignored\n", val); + return false; + } + +- act->count = btn; ++ act->count = (uint8_t) val; + return true; + } +- return ReportIllegal(keymap, action->type, field); ++ ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static const LookupEntry ptrDflts[] = { +@@ -588,10 +518,10 @@ HandleSetPtrDflt(struct xkb_keymap *keym + unsigned int val; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + + if (!ExprResolveEnum(keymap->ctx, value, &val, ptrDflts)) +- return ReportMismatch(keymap, action->type, field, ++ return ReportMismatch(keymap->ctx, action->type, field, + "pointer component"); + return true; + } +@@ -600,7 +530,7 @@ HandleSetPtrDflt(struct xkb_keymap *keym + int btn; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + + if (value->expr.op == EXPR_NEGATE || + value->expr.op == EXPR_UNARY_PLUS) { +@@ -613,7 +543,7 @@ HandleSetPtrDflt(struct xkb_keymap *keym + } + + if (!ExprResolveButton(keymap->ctx, button, &btn)) +- return ReportMismatch(keymap, action->type, field, ++ return ReportMismatch(keymap->ctx, action->type, field, + "integer (range 1..5)"); + + if (btn < 0 || btn > 5) { +@@ -633,7 +563,7 @@ HandleSetPtrDflt(struct xkb_keymap *keym + return true; + } + +- return ReportIllegal(keymap, action->type, field); ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static bool +@@ -648,7 +578,7 @@ HandleSwitchScreen(struct xkb_keymap *ke + int val; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + + if (value->expr.op == EXPR_NEGATE || + value->expr.op == EXPR_UNARY_PLUS) { +@@ -661,7 +591,7 @@ HandleSwitchScreen(struct xkb_keymap *ke + } + + if (!ExprResolveInteger(keymap->ctx, scrn, &val)) +- return ReportMismatch(keymap, action->type, field, ++ return ReportMismatch(keymap->ctx, action->type, field, + "integer (0..255)"); + + if (val < 0 || val > 255) { +@@ -675,23 +605,12 @@ HandleSwitchScreen(struct xkb_keymap *ke + return true; + } + else if (field == ACTION_FIELD_SAME) { +- bool set; +- +- if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); +- +- if (!ExprResolveBoolean(keymap->ctx, value, &set)) +- return ReportMismatch(keymap, action->type, field, "boolean"); +- +- if (set) +- act->flags &= ~ACTION_SAME_SCREEN; +- else +- act->flags |= ACTION_SAME_SCREEN; +- +- return true; ++ return CheckBooleanFlag(keymap->ctx, action->type, field, ++ ACTION_SAME_SCREEN, array_ndx, value, ++ &act->flags); + } + +- return ReportIllegal(keymap, action->type, field); ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static bool +@@ -705,17 +624,21 @@ HandleSetLockControls(struct xkb_keymap + unsigned int mask; + + if (array_ndx) +- return ReportActionNotArray(keymap, action->type, field); ++ return ReportActionNotArray(keymap->ctx, action->type, field); + + if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames)) +- return ReportMismatch(keymap, action->type, field, ++ return ReportMismatch(keymap->ctx, action->type, field, + "controls mask"); + + act->ctrls = mask; + return true; + } ++ else if (field == ACTION_FIELD_AFFECT) { ++ return CheckAffectField(keymap->ctx, action->type, array_ndx, value, ++ &act->flags); ++ } + +- return ReportIllegal(keymap, action->type, field); ++ return ReportIllegal(keymap->ctx, action->type, field); + } + + static bool +@@ -728,8 +651,11 @@ HandlePrivate(struct xkb_keymap *keymap, + if (field == ACTION_FIELD_TYPE) { + int type; + ++ if (array_ndx) ++ return ReportActionNotArray(keymap->ctx, action->type, field); ++ + if (!ExprResolveInteger(keymap->ctx, value, &type)) +- return ReportMismatch(keymap, ACTION_TYPE_PRIVATE, field, "integer"); ++ return ReportMismatch(keymap->ctx, ACTION_TYPE_PRIVATE, field, "integer"); + + if (type < 0 || type > 255) { + log_err(keymap->ctx, +@@ -764,17 +690,17 @@ HandlePrivate(struct xkb_keymap *keymap, + if (array_ndx == NULL) { + xkb_atom_t val; + const char *str; +- int len; ++ size_t len; + + if (!ExprResolveString(keymap->ctx, value, &val)) +- return ReportMismatch(keymap, action->type, field, "string"); ++ return ReportMismatch(keymap->ctx, action->type, field, "string"); + + str = xkb_atom_text(keymap->ctx, val); + len = strlen(str); + if (len < 1 || len > 7) { + log_warn(keymap->ctx, + "A private action has 7 data bytes; " +- "Extra %d bytes ignored\n", len - 6); ++ "Illegal data ignored\n"); + return false; + } + +@@ -791,7 +717,7 @@ HandlePrivate(struct xkb_keymap *keymap, + return false; + } + +- if (ndx < 0 || ndx >= sizeof(act->data)) { ++ if (ndx < 0 || (size_t) ndx >= sizeof(act->data)) { + log_err(keymap->ctx, + "The data for a private action is %lu bytes long; " + "Attempt to use data[%d] ignored\n", +@@ -800,7 +726,7 @@ HandlePrivate(struct xkb_keymap *keymap, + } + + if (!ExprResolveInteger(keymap->ctx, value, &datum)) +- return ReportMismatch(keymap, act->type, field, "integer"); ++ return ReportMismatch(keymap->ctx, act->type, field, "integer"); + + if (datum < 0 || datum > 255) { + log_err(keymap->ctx, +@@ -814,7 +740,7 @@ HandlePrivate(struct xkb_keymap *keymap, + } + } + +- return ReportIllegal(keymap, ACTION_TYPE_NONE, field); ++ return ReportIllegal(keymap->ctx, ACTION_TYPE_NONE, field); + } + + typedef bool (*actionHandler)(struct xkb_keymap *keymap, +@@ -825,12 +751,12 @@ typedef bool (*actionHandler)(struct xkb + + static const actionHandler handleAction[_ACTION_TYPE_NUM_ENTRIES] = { + [ACTION_TYPE_NONE] = HandleNoAction, +- [ACTION_TYPE_MOD_SET] = HandleSetLatchMods, +- [ACTION_TYPE_MOD_LATCH] = HandleSetLatchMods, +- [ACTION_TYPE_MOD_LOCK] = HandleLockMods, +- [ACTION_TYPE_GROUP_SET] = HandleSetLatchGroup, +- [ACTION_TYPE_GROUP_LATCH] = HandleSetLatchGroup, +- [ACTION_TYPE_GROUP_LOCK] = HandleLockGroup, ++ [ACTION_TYPE_MOD_SET] = HandleSetLatchLockMods, ++ [ACTION_TYPE_MOD_LATCH] = HandleSetLatchLockMods, ++ [ACTION_TYPE_MOD_LOCK] = HandleSetLatchLockMods, ++ [ACTION_TYPE_GROUP_SET] = HandleSetLatchLockGroup, ++ [ACTION_TYPE_GROUP_LATCH] = HandleSetLatchLockGroup, ++ [ACTION_TYPE_GROUP_LOCK] = HandleSetLatchLockGroup, + [ACTION_TYPE_PTR_MOVE] = HandleMovePtr, + [ACTION_TYPE_PTR_BUTTON] = HandlePtrBtn, + [ACTION_TYPE_PTR_LOCK] = HandlePtrBtn, +@@ -921,7 +847,6 @@ HandleActionDef(ExprDef *def, struct xkb + return true; + } + +- + bool + SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field, + ExprDef *array_ndx, ExprDef *value, ActionsInfo *info) +--- a/src/3rdparty/xkbcommon/src/xkbcomp/ast-build.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/ast-build.c +@@ -53,7 +53,6 @@ + + #include "xkbcomp-priv.h" + #include "ast-build.h" +-#include "parser-priv.h" + #include "include.h" + + ParseCommon * +@@ -202,7 +201,7 @@ ExprCreateKeysymList(xkb_keysym_t sym) + ExprDef * + ExprCreateMultiKeysymList(ExprDef *expr) + { +- size_t nLevels = darray_size(expr->keysym_list.symsMapIndex); ++ unsigned nLevels = darray_size(expr->keysym_list.symsMapIndex); + + darray_resize(expr->keysym_list.symsMapIndex, 1); + darray_resize(expr->keysym_list.symsNumEntries, 1); +@@ -215,7 +214,7 @@ ExprCreateMultiKeysymList(ExprDef *expr) + ExprDef * + ExprAppendKeysymList(ExprDef *expr, xkb_keysym_t sym) + { +- size_t nSyms = darray_size(expr->keysym_list.syms); ++ unsigned nSyms = darray_size(expr->keysym_list.syms); + + darray_append(expr->keysym_list.symsMapIndex, nSyms); + darray_append(expr->keysym_list.symsNumEntries, 1); +@@ -227,8 +226,8 @@ ExprAppendKeysymList(ExprDef *expr, xkb_ + ExprDef * + ExprAppendMultiKeysymList(ExprDef *expr, ExprDef *append) + { +- size_t nSyms = darray_size(expr->keysym_list.syms); +- size_t numEntries = darray_size(append->keysym_list.syms); ++ unsigned nSyms = darray_size(expr->keysym_list.syms); ++ unsigned numEntries = darray_size(append->keysym_list.syms); + + darray_append(expr->keysym_list.symsMapIndex, nSyms); + darray_append(expr->keysym_list.symsNumEntries, numEntries); +@@ -356,7 +355,7 @@ SymbolsCreate(xkb_atom_t keyName, VarDef + } + + GroupCompatDef * +-GroupCompatCreate(int group, ExprDef *val) ++GroupCompatCreate(unsigned group, ExprDef *val) + { + GroupCompatDef *def = malloc(sizeof(*def)); + if (!def) +@@ -372,7 +371,7 @@ GroupCompatCreate(int group, ExprDef *va + } + + ModMapDef * +-ModMapCreate(uint32_t modifier, ExprDef *keys) ++ModMapCreate(xkb_atom_t modifier, ExprDef *keys) + { + ModMapDef *def = malloc(sizeof(*def)); + if (!def) +@@ -404,7 +403,7 @@ LedMapCreate(xkb_atom_t name, VarDef *bo + } + + LedNameDef * +-LedNameCreate(int ndx, ExprDef *name, bool virtual) ++LedNameCreate(unsigned ndx, ExprDef *name, bool virtual) + { + LedNameDef *def = malloc(sizeof(*def)); + if (!def) +@@ -496,8 +495,8 @@ err: + } + + XkbFile * +-XkbFileCreate(struct xkb_context *ctx, enum xkb_file_type type, char *name, +- ParseCommon *defs, enum xkb_map_flags flags) ++XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs, ++ enum xkb_map_flags flags) + { + XkbFile *file; + +@@ -533,7 +532,7 @@ XkbFileFromComponents(struct xkb_context + if (!include) + goto err; + +- file = XkbFileCreate(ctx, type, NULL, &include->common, 0); ++ file = XkbFileCreate(type, NULL, (ParseCommon *) include, 0); + if (!file) { + FreeInclude(include); + goto err; +@@ -542,7 +541,7 @@ XkbFileFromComponents(struct xkb_context + defs = AppendStmt(defs, &file->common); + } + +- file = XkbFileCreate(ctx, FILE_TYPE_KEYMAP, NULL, defs, 0); ++ file = XkbFileCreate(FILE_TYPE_KEYMAP, NULL, defs, 0); + if (!file) + goto err; + +@@ -565,7 +564,7 @@ FreeExpr(ExprDef *expr) + case EXPR_UNARY_PLUS: + case EXPR_NOT: + case EXPR_INVERT: +- FreeStmt(&expr->unary.child->common); ++ FreeStmt((ParseCommon *) expr->unary.child); + break; + + case EXPR_DIVIDE: +@@ -573,16 +572,16 @@ FreeExpr(ExprDef *expr) + case EXPR_SUBTRACT: + case EXPR_MULTIPLY: + case EXPR_ASSIGN: +- FreeStmt(&expr->binary.left->common); +- FreeStmt(&expr->binary.right->common); ++ FreeStmt((ParseCommon *) expr->binary.left); ++ FreeStmt((ParseCommon *) expr->binary.right); + break; + + case EXPR_ACTION_DECL: +- FreeStmt(&expr->action.args->common); ++ FreeStmt((ParseCommon *) expr->action.args); + break; + + case EXPR_ARRAY_REF: +- FreeStmt(&expr->array_ref.entry->common); ++ FreeStmt((ParseCommon *) expr->array_ref.entry); + break; + + case EXPR_KEYSYM_LIST: +@@ -619,12 +618,10 @@ void + FreeStmt(ParseCommon *stmt) + { + ParseCommon *next; +- YYSTYPE u; + + while (stmt) + { + next = stmt->next; +- u.any = stmt; + + switch (stmt->type) { + case STMT_INCLUDE: +@@ -633,36 +630,36 @@ FreeStmt(ParseCommon *stmt) + stmt = NULL; + break; + case STMT_EXPR: +- FreeExpr(u.expr); ++ FreeExpr((ExprDef *) stmt); + break; + case STMT_VAR: +- FreeStmt(&u.var->name->common); +- FreeStmt(&u.var->value->common); ++ FreeStmt((ParseCommon *) ((VarDef *) stmt)->name); ++ FreeStmt((ParseCommon *) ((VarDef *) stmt)->value); + break; + case STMT_TYPE: +- FreeStmt(&u.keyType->body->common); ++ FreeStmt((ParseCommon *) ((KeyTypeDef *) stmt)->body); + break; + case STMT_INTERP: +- FreeStmt(&u.interp->match->common); +- FreeStmt(&u.interp->def->common); ++ FreeStmt((ParseCommon *) ((InterpDef *) stmt)->match); ++ FreeStmt((ParseCommon *) ((InterpDef *) stmt)->def); + break; + case STMT_VMOD: +- FreeStmt(&u.vmod->value->common); ++ FreeStmt((ParseCommon *) ((VModDef *) stmt)->value); + break; + case STMT_SYMBOLS: +- FreeStmt(&u.syms->symbols->common); ++ FreeStmt((ParseCommon *) ((SymbolsDef *) stmt)->symbols); + break; + case STMT_MODMAP: +- FreeStmt(&u.modMask->keys->common); ++ FreeStmt((ParseCommon *) ((ModMapDef *) stmt)->keys); + break; + case STMT_GROUP_COMPAT: +- FreeStmt(&u.groupCompat->def->common); ++ FreeStmt((ParseCommon *) ((GroupCompatDef *) stmt)->def); + break; + case STMT_LED_MAP: +- FreeStmt(&u.ledMap->body->common); ++ FreeStmt((ParseCommon *) ((LedMapDef *) stmt)->body); + break; + case STMT_LED_NAME: +- FreeStmt(&u.ledName->name->common); ++ FreeStmt((ParseCommon *) ((LedNameDef *) stmt)->name); + break; + default: + break; +--- a/src/3rdparty/xkbcommon/src/xkbcomp/ast-build.h ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/ast-build.h +@@ -98,23 +98,23 @@ SymbolsDef * + SymbolsCreate(xkb_atom_t keyName, VarDef *symbols); + + GroupCompatDef * +-GroupCompatCreate(int group, ExprDef *def); ++GroupCompatCreate(unsigned group, ExprDef *def); + + ModMapDef * +-ModMapCreate(uint32_t modifier, ExprDef *keys); ++ModMapCreate(xkb_atom_t modifier, ExprDef *keys); + + LedMapDef * + LedMapCreate(xkb_atom_t name, VarDef *body); + + LedNameDef * +-LedNameCreate(int ndx, ExprDef *name, bool virtual); ++LedNameCreate(unsigned ndx, ExprDef *name, bool virtual); + + IncludeStmt * + IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge); + + XkbFile * +-XkbFileCreate(struct xkb_context *ctx, enum xkb_file_type type, char *name, +- ParseCommon *defs, enum xkb_map_flags flags); ++XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs, ++ enum xkb_map_flags flags); + + void + FreeStmt(ParseCommon *stmt); +--- a/src/3rdparty/xkbcommon/src/xkbcomp/ast.h ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/ast.h +@@ -143,9 +143,7 @@ expr_op_type_to_string(enum expr_op_type + const char * + expr_value_type_to_string(enum expr_value_type type); + +-/* This struct contains fields common to all other AST nodes. It is only +- * ever embedded in other structs, so save some memory by packing it. */ +-typedef struct ATTR_PACKED _ParseCommon { ++typedef struct _ParseCommon { + struct _ParseCommon *next; + enum stmt_type type; + } ParseCommon; +@@ -226,7 +224,7 @@ typedef struct { + typedef struct { + ExprCommon expr; + darray(xkb_keysym_t) syms; +- darray(int) symsMapIndex; ++ darray(unsigned int) symsMapIndex; + darray(unsigned int) symsNumEntries; + } ExprKeysymList; + +@@ -299,7 +297,7 @@ typedef struct { + typedef struct { + ParseCommon common; + enum merge_mode merge; +- int group; ++ unsigned group; + ExprDef *def; + } GroupCompatDef; + +@@ -314,7 +312,7 @@ typedef struct { + typedef struct { + ParseCommon common; + enum merge_mode merge; +- int ndx; ++ unsigned ndx; + ExprDef *name; + bool virtual; + } LedNameDef; +--- a/src/3rdparty/xkbcommon/src/xkbcomp/compat.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/compat.c +@@ -54,179 +54,6 @@ + #include "vmod.h" + #include "include.h" + +-/* +- * The xkb_compat section +- * ===================== +- * This section is the third to be processed, after xkb_keycodes and +- * xkb_types. +- * +- * Interpret statements +- * -------------------- +- * Statements of the form: +- * interpret Num_Lock+Any { ... } +- * interpret Shift_Lock+AnyOf(Shift+Lock) { ... } +- * +- * The xkb_symbols section (see symbols.c) allows the keymap author to do, +- * among other things, the following for each key: +- * - Bind an action, like SetMods or LockGroup, to the key. Actions, like +- * symbols, are specified for each level of each group in the key +- * separately. +- * - Add a virtual modifier to the key's virtual modifier mapping (vmodmap). +- * - Specify whether the key should repeat or not. +- * +- * However, doing this for each key (or level) is tedious and inflexible. +- * Interpret's are a mechanism to apply these settings to a bunch of +- * keys/levels at once. +- * +- * Each interpret specifies a condition by which it attaches to certain +- * levels. The condition consists of two parts: +- * - A keysym. If the level has a different (or more than one) keysym, the +- * match failes. Leaving out the keysym is equivalent to using the +- * NoSymbol keysym, which always matches successfully. +- * - A modifier predicate. The predicate consists of a matching operation +- * and a mask of (real) modifiers. The modifers are matched against the +- * key's modifier map (modmap). The matching operation can be one of the +- * following: +- * + AnyOfOrNone - The modmap must either be empty or include at least +- * one of the specified modifiers. +- * + AnyOf - The modmap must include at least one of the specified +- * modifiers. +- * + NoneOf - The modmap must not include any of the specified modifiers. +- * + AllOf - The modmap must include all of the specified modifiers (but +- * may include others as well). +- * + Exactly - The modmap must be exactly the same as the specified +- * modifiers. +- * Leaving out the predicate is equivalent to usign AnyOfOrNone while +- * specifying all modifiers. Leaving out just the matching condtition +- * is equivalent to using Exactly. +- * An interpret may also include "useModMapMods = level1;" - see below. +- * +- * If a level fulfils the conditions of several interpret's, only the +- * most specific one is used: +- * - A specific keysym will always match before a generic NoSymbol +- * condition. +- * - If the keysyms are the same, the interpret with the more specific +- * matching operation is used. The above list is sorted from least to +- * most specific. +- * - If both the keysyms and the matching operations are the same (but the +- * modifiers are different), the first interpret is used. +- * +- * As described above, once an interpret "attaches" to a level, it can bind +- * an action to that level, add one virtual modifier to the key's vmodmap, +- * or set the key's repeat setting. You should note the following: +- * - The key repeat is a property of the entire key; it is not level-specific. +- * In order to avoid confusion, it is only inspected for the first level of +- * the first group; the interpret's repeat setting is ignored when applied +- * to other levels. +- * - If one of the above fields was set directly for a key in xkb_symbols, +- * the explicit setting takes precedence over the interpret. +- * +- * The body of the statment may include statements of the following +- * forms (all of which are optional): +- * +- * - useModMapMods statement: +- * useModMapMods = level1; +- * +- * When set to 'level1', the interpret will only match levels which are +- * the first level of the first group of the keys. This can be useful in +- * conjunction with e.g. a virtualModifier statement. +- * +- * - action statement: +- * action = LockMods(modifiers=NumLock); +- * +- * Bind this action to the matching levels. +- * +- * - virtual modifier statement: +- * virtualModifier = NumLock; +- * +- * Add this virtual modifier to the key's vmodmap. The given virtual +- * modifier must be declared at the top level of the file with a +- * virtual_modifiers statement, e.g.: +- * virtual_modifiers NumLock; +- * +- * - repeat statement: +- * repeat = True; +- * +- * Set whether the key should repeat or not. Must be a boolean value. +- * +- * Led map statements +- * ------------------------ +- * Statements of the form: +- * indicator "Shift Lock" { ... } +- * +- * This statement specifies the behavior and binding of the LED (a.k.a +- * indicator) with the given name ("Shift Lock" above). The name should +- * have been declared previously in the xkb_keycodes section (see Led +- * name statement), and given an index there. If it wasn't, it is created +- * with the next free index. +- * The body of the statement describes the conditions of the keyboard +- * state which will cause the LED to be lit. It may include the following +- * statements: +- * +- * - modifiers statment: +- * modifiers = ScrollLock; +- * +- * If the given modifiers are in the required state (see below), the +- * led is lit. +- * +- * - whichModifierState statment: +- * whichModState = Latched + Locked; +- * +- * Can be any combination of: +- * base, latched, locked, effective +- * any (i.e. all of the above) +- * none (i.e. none of the above) +- * compat (legacy value, treated as effective) +- * This will cause the respective portion of the modifer state (see +- * struct xkb_state) to be matched against the modifiers given in the +- * "modifiers" statement. +- * +- * Here's a simple example: +- * indicator "Num Lock" { +- * modifiers = NumLock; +- * whichModState = Locked; +- * }; +- * Whenever the NumLock modifier is locked, the Num Lock LED will light +- * up. +- * +- * - groups statment: +- * groups = All - group1; +- * +- * If the given groups are in the required state (see below), the led +- * is lit. +- * +- * - whichGroupState statment: +- * whichGroupState = Effective; +- * +- * Can be any combination of: +- * base, latched, locked, effective +- * any (i.e. all of the above) +- * none (i.e. none of the above) +- * This will cause the respective portion of the group state (see +- * struct xkb_state) to be matched against the groups given in the +- * "groups" statement. +- * +- * Note: the above conditions are disjunctive, i.e. if any of them are +- * satisfied the led is lit. +- * +- * Virtual modifier statements +- * --------------------------- +- * Statements of the form: +- * virtual_modifiers LControl; +- * +- * Can appear in the xkb_types, xkb_compat, xkb_symbols sections. +- * TODO +- * +- * Effect on keymap +- * ---------------- +- * After all of the xkb_compat sections have been compiled, the following +- * members of struct xkb_keymap are finalized: +- * darray(struct xkb_sym_interpret) sym_interprets; +- * darray(struct xkb_led) leds; +- * char *compat_section_name; +- * TODO: virtual modifiers. +- */ +- + enum si_field { + SI_FIELD_VIRTUAL_MOD = (1 << 0), + SI_FIELD_ACTION = (1 << 1), +@@ -555,16 +382,28 @@ MergeIncludedCompatMaps(CompatInfo *into + from->name = NULL; + } + +- darray_foreach(si, from->interps) { +- si->merge = (merge == MERGE_DEFAULT ? si->merge : merge); +- if (!AddInterp(into, si, false)) +- into->errorCount++; ++ if (darray_empty(into->interps)) { ++ into->interps = from->interps; ++ darray_init(from->interps); ++ } ++ else { ++ darray_foreach(si, from->interps) { ++ si->merge = (merge == MERGE_DEFAULT ? si->merge : merge); ++ if (!AddInterp(into, si, false)) ++ into->errorCount++; ++ } + } + +- darray_foreach(ledi, from->leds) { +- ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge); +- if (!AddLedMap(into, ledi, false)) +- into->errorCount++; ++ if (darray_empty(into->leds)) { ++ into->leds = from->leds; ++ darray_init(from->leds); ++ } ++ else { ++ darray_foreach(ledi, from->leds) { ++ ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge); ++ if (!AddLedMap(into, ledi, false)) ++ into->errorCount++; ++ } + } + } + +@@ -929,7 +768,7 @@ HandleCompatMapFile(CompatInfo *info, Xk + ok = HandleGlobalVar(info, (VarDef *) stmt); + break; + case STMT_VMOD: +- ok = HandleVModDef(info->keymap, (VModDef *) stmt); ++ ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge); + break; + default: + log_err(info->keymap->ctx, +--- a/src/3rdparty/xkbcommon/src/xkbcomp/expr.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/expr.c +@@ -116,7 +116,7 @@ LookupModMask(struct xkb_context *ctx, c + if (ndx == XKB_MOD_INVALID) + return false; + +- *val_rtrn = (1 << ndx); ++ *val_rtrn = (1u << ndx); + return true; + } + +@@ -427,14 +427,8 @@ ExprResolveLevel(struct xkb_context *ctx + bool + ExprResolveButton(struct xkb_context *ctx, const ExprDef *expr, int *btn_rtrn) + { +- int result; +- +- if (!ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup, +- buttonNames)) +- return false; +- +- *btn_rtrn = result; +- return true; ++ return ExprResolveIntegerLookup(ctx, expr, btn_rtrn, SimpleLookup, ++ buttonNames); + } + + bool +--- a/src/3rdparty/xkbcommon/src/xkbcomp/keycodes.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/keycodes.c +@@ -29,79 +29,6 @@ + #include "expr.h" + #include "include.h" + +-/* +- * The xkb_keycodes section +- * ======================== +- * +- * This is the simplest section type, and is the first one to be +- * compiled. The purpose of this is mostly to map between the +- * hardware/evdev scancodes and xkb keycodes. Each key is given a name +- * by which it can be referred to later, e.g. in the symbols section. +- * +- * Keycode statements +- * ------------------ +- * Statements of the form: +- * = 49; +- * = 10; +- * +- * The above would let 49 and 10 be valid keycodes in the keymap, and +- * assign them the names TLDE and AE01 respectively. The format is +- * always used to refer to a key by name. +- * +- * [ The naming convention just denoted the position of the key +- * in the main alphanumric section of the keyboard, with the two letters +- * specifying the row and the two digits specifying the column, from +- * the bottom left.] +- * +- * In the common case this just maps to the evdev scancodes from +- * /usr/include/linux/input.h, e.g. the following definitions: +- * #define KEY_GRAVE 41 +- * #define KEY_1 2 +- * Similar definitions appear in the xf86-input-keyboard driver. Note +- * that in all current keymaps there's a constant offset of 8 (for +- * historical reasons). +- * +- * If there's a conflict, like the same name given to different keycodes, +- * or same keycode given different names, it is resolved according to the +- * merge mode which applies to the definitions. +- * +- * Alias statements +- * ---------------- +- * Statements of the form: +- * alias = ; +- * +- * Allows to refer to a previously defined key (here ) by another +- * name (here ). Conflicts are handled similarly. +- * +- * LED name statements +- * ------------------------- +- * Statements of the form: +- * indicator 1 = "Caps Lock"; +- * indicator 2 = "Num Lock"; +- * indicator 3 = "Scroll Lock"; +- * +- * Assigns a name to the keyboard LED (a.k.a indicator) with the given index. +- * The led may be referred by this name later in the compat section +- * and by the user. +- * +- * Effect on the keymap +- * -------------------- +- * After all of the xkb_keycodes sections have been compiled, the +- * following members of struct xkb_keymap are finalized: +- * xkb_keycode_t min_key_code; +- * xkb_keycode_t max_key_code; +- * unsigned int num_aliases; +- * struct xkb_key_alias *key_aliases; +- * char *keycodes_section_name; +- * The 'name' field of leds declared in xkb_keycodes: +- * darray(struct xkb_led) leds; +- * Further, the array of keys: +- * struct xkb_key *keys; +- * had been resized to its final size (i.e. all of the xkb_key objects are +- * referable by their keycode). However the objects themselves do not +- * contain any useful information besides the key name at this point. +- */ +- + typedef struct { + enum merge_mode merge; + +@@ -322,7 +249,7 @@ AddKeyName(KeyNamesInfo *info, xkb_keyco + + /***====================================================================***/ + +-static int ++static bool + HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge); + + static void +@@ -459,7 +386,7 @@ HandleKeycodeDef(KeyNamesInfo *info, Key + return AddKeyName(info, stmt->value, stmt->name, merge, false, true); + } + +-static int ++static bool + HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge) + { + AliasInfo *old, new; +@@ -499,7 +426,7 @@ HandleAliasDef(KeyNamesInfo *info, KeyAl + return true; + } + +-static int ++static bool + HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt) + { + const char *elem, *field; +@@ -524,7 +451,7 @@ HandleKeyNameVar(KeyNamesInfo *info, Var + return true; + } + +-static int ++static bool + HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def, + enum merge_mode merge) + { +--- a/src/3rdparty/xkbcommon/src/xkbcomp/keymap-dump.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/keymap-dump.c +@@ -92,7 +92,7 @@ check_write_buf(struct buf *buf, const c + if (printed < 0) + goto err; + +- if (printed >= available) ++ if ((size_t) printed >= available) + if (!do_realloc(buf, printed)) + goto err; + +@@ -103,7 +103,7 @@ check_write_buf(struct buf *buf, const c + printed = vsnprintf(buf->buf + buf->size, available, fmt, args); + va_end(args); + +- if (printed >= available || printed < 0) ++ if (printed < 0 || (size_t) printed >= available) + goto err; + + buf->size += printed; +@@ -273,6 +273,20 @@ write_led_map(struct xkb_keymap *keymap, + return true; + } + ++static const char * ++affect_lock_text(enum xkb_action_flags flags) ++{ ++ switch (flags & (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK)) { ++ case ACTION_LOCK_NO_UNLOCK: ++ return ",affect=lock"; ++ case ACTION_LOCK_NO_LOCK: ++ return ",affect=unlock"; ++ case ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK: ++ return ",affect=neither"; ++ } ++ return ""; ++} ++ + static bool + write_action(struct xkb_keymap *keymap, struct buf *buf, + const union xkb_action *action, +@@ -289,20 +303,17 @@ write_action(struct xkb_keymap *keymap, + type = ActionTypeText(action->type); + + switch (action->type) { ++ case ACTION_TYPE_MOD_LOCK: + case ACTION_TYPE_MOD_SET: + case ACTION_TYPE_MOD_LATCH: +- case ACTION_TYPE_MOD_LOCK: + if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAP) + args = "modMapMods"; + else + args = ModMaskText(keymap, action->mods.mods.mods); +- write_buf(buf, "%s%s(modifiers=%s%s%s)%s", prefix, type, args, +- (action->type != ACTION_TYPE_MOD_LOCK && +- (action->mods.flags & ACTION_LOCK_CLEAR)) ? +- ",clearLocks" : "", +- (action->type != ACTION_TYPE_MOD_LOCK && +- (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? +- ",latchToLock" : "", ++ write_buf(buf, "%s%s(modifiers=%s%s%s%s)%s", prefix, type, args, ++ (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "", ++ (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "", ++ (action->type == ACTION_TYPE_MOD_LOCK) ? affect_lock_text(action->mods.flags) : "", + suffix); + break; + +@@ -310,16 +321,10 @@ write_action(struct xkb_keymap *keymap, + case ACTION_TYPE_GROUP_LATCH: + case ACTION_TYPE_GROUP_LOCK: + write_buf(buf, "%s%s(group=%s%d%s%s)%s", prefix, type, +- (!(action->group.flags & ACTION_ABSOLUTE_SWITCH) && +- action->group.group > 0) ? "+" : "", +- (action->group.flags & ACTION_ABSOLUTE_SWITCH) ? +- action->group.group + 1 : action->group.group, +- (action->type != ACTION_TYPE_GROUP_LOCK && +- (action->group.flags & ACTION_LOCK_CLEAR)) ? +- ",clearLocks" : "", +- (action->type != ACTION_TYPE_GROUP_LOCK && +- (action->group.flags & ACTION_LATCH_TO_LOCK)) ? +- ",latchToLock" : "", ++ (!(action->group.flags & ACTION_ABSOLUTE_SWITCH) && action->group.group > 0) ? "+" : "", ++ (action->group.flags & ACTION_ABSOLUTE_SWITCH) ? action->group.group + 1 : action->group.group, ++ (action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "", ++ (action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "", + suffix); + break; + +@@ -329,35 +334,17 @@ write_action(struct xkb_keymap *keymap, + + case ACTION_TYPE_PTR_MOVE: + write_buf(buf, "%s%s(x=%s%d,y=%s%d%s)%s", prefix, type, +- (!(action->ptr.flags & ACTION_ABSOLUTE_X) && +- action->ptr.x >= 0) ? "+" : "", ++ (!(action->ptr.flags & ACTION_ABSOLUTE_X) && action->ptr.x >= 0) ? "+" : "", + action->ptr.x, +- (!(action->ptr.flags & ACTION_ABSOLUTE_Y) && +- action->ptr.y >= 0) ? "+" : "", ++ (!(action->ptr.flags & ACTION_ABSOLUTE_Y) && action->ptr.y >= 0) ? "+" : "", + action->ptr.y, +- (action->ptr.flags & ACTION_NO_ACCEL) ? ",!accel" : "", ++ (action->ptr.flags & ACTION_ACCEL) ? "" : ",!accel", + suffix); + break; + + case ACTION_TYPE_PTR_LOCK: +- switch (action->btn.flags & +- (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK)) { +- case ACTION_LOCK_NO_UNLOCK: +- args = ",affect=lock"; +- break; +- +- case ACTION_LOCK_NO_LOCK: +- args = ",affect=unlock"; +- break; +- +- case ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK: +- args = ",affect=neither"; +- break; +- +- default: +- args = ",affect=both"; +- break; +- } ++ args = affect_lock_text(action->btn.flags); ++ /* fallthrough */ + case ACTION_TYPE_PTR_BUTTON: + write_buf(buf, "%s%s(button=", prefix, type); + if (action->btn.button > 0 && action->btn.button <= 5) +@@ -374,25 +361,25 @@ write_action(struct xkb_keymap *keymap, + case ACTION_TYPE_PTR_DEFAULT: + write_buf(buf, "%s%s(", prefix, type); + write_buf(buf, "affect=button,button=%s%d", +- (!(action->dflt.flags & ACTION_ABSOLUTE_SWITCH) && +- action->dflt.value >= 0) ? "+" : "", ++ (!(action->dflt.flags & ACTION_ABSOLUTE_SWITCH) && action->dflt.value >= 0) ? "+" : "", + action->dflt.value); + write_buf(buf, ")%s", suffix); + break; + + case ACTION_TYPE_SWITCH_VT: + write_buf(buf, "%s%s(screen=%s%d,%ssame)%s", prefix, type, +- (!(action->screen.flags & ACTION_ABSOLUTE_SWITCH) && +- action->screen.screen >= 0) ? "+" : "", ++ (!(action->screen.flags & ACTION_ABSOLUTE_SWITCH) && action->screen.screen >= 0) ? "+" : "", + action->screen.screen, +- (action->screen.flags & ACTION_SAME_SCREEN) ? "!" : "", ++ (action->screen.flags & ACTION_SAME_SCREEN) ? "" : "!", + suffix); + break; + + case ACTION_TYPE_CTRL_SET: + case ACTION_TYPE_CTRL_LOCK: +- write_buf(buf, "%s%s(controls=%s)%s", prefix, type, +- ControlMaskText(keymap->ctx, action->ctrls.ctrls), suffix); ++ write_buf(buf, "%s%s(controls=%s%s)%s", prefix, type, ++ ControlMaskText(keymap->ctx, action->ctrls.ctrls), ++ (action->type == ACTION_TYPE_CTRL_LOCK) ? affect_lock_text(action->ctrls.flags) : "", ++ suffix); + break; + + case ACTION_TYPE_NONE: +@@ -429,7 +416,7 @@ write_compat(struct xkb_keymap *keymap, + write_buf(buf, "\tinterpret.useModMapMods= AnyLevel;\n"); + write_buf(buf, "\tinterpret.repeat= False;\n"); + +- for (int i = 0; i < keymap->num_sym_interprets; i++) { ++ for (unsigned i = 0; i < keymap->num_sym_interprets; i++) { + const struct xkb_sym_interpret *si = &keymap->sym_interprets[i]; + + write_buf(buf, "\tinterpret %s+%s(%s) {\n", +@@ -635,7 +622,7 @@ write_symbols(struct xkb_keymap *keymap, + continue; + + darray_enumerate(i, mod, keymap->mods) +- if (key->modmap & (1 << i)) ++ if (key->modmap & (1u << i)) + write_buf(buf, "\tmodifier_map %s { %s };\n", + xkb_atom_text(keymap->ctx, mod->name), + KeyNameText(keymap->ctx, key->name)); +--- a/src/3rdparty/xkbcommon/src/xkbcomp/keymap.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/keymap.c +@@ -39,7 +39,7 @@ ComputeEffectiveMask(struct xkb_keymap * + mods->mask = mods->mods & MOD_REAL_MASK_ALL; + + darray_enumerate(i, mod, keymap->mods) +- if (mods->mods & (1 << i)) ++ if (mods->mods & (1u << i)) + mods->mask |= mod->mapping; + } + +@@ -92,7 +92,7 @@ FindInterpForKey(struct xkb_keymap *keym + * sym_interprets array from the most specific to the least specific, + * such that when we find a match we return immediately. + */ +- for (int i = 0; i < keymap->num_sym_interprets; i++) { ++ for (unsigned i = 0; i < keymap->num_sym_interprets; i++) { + const struct xkb_sym_interpret *interp = &keymap->sym_interprets[i]; + + xkb_mod_mask_t mods; +@@ -158,7 +158,7 @@ ApplyInterpsToKey(struct xkb_keymap *key + + if ((group == 0 && level == 0) || !interp->level_one_only) + if (interp->virtual_mod != XKB_MOD_INVALID) +- vmodmap |= (1 << interp->virtual_mod); ++ vmodmap |= (1u << interp->virtual_mod); + + if (interp->action.type != ACTION_TYPE_NONE) + key->groups[group].levels[level].action = interp->action; +@@ -194,7 +194,7 @@ UpdateDerivedKeymapFields(struct xkb_key + /* Update keymap->mods, the virtual -> real mod mapping. */ + xkb_foreach_key(key, keymap) + darray_enumerate(i, mod, keymap->mods) +- if (key->vmodmap & (1 << i)) ++ if (key->vmodmap & (1u << i)) + mod->mapping |= key->modmap; + + /* Now update the level masks for all the types to reflect the vmods. */ +--- a/src/3rdparty/xkbcommon/src/xkbcomp/keywords.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/keywords.c +@@ -339,10 +339,9 @@ keyword_gperf_lookup (register const cha + + + int +-keyword_to_token(const char *string) ++keyword_to_token(const char *string, unsigned int len) + { +- const struct keyword_tok *kt; +- kt = keyword_gperf_lookup(string, strlen(string)); ++ const struct keyword_tok *kt = keyword_gperf_lookup(string, len); + if (!kt) + return -1; + return kt->tok; +--- a/src/3rdparty/xkbcommon/src/xkbcomp/parser-priv.h ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/parser-priv.h +@@ -27,24 +27,18 @@ + #ifndef XKBCOMP_PARSER_PRIV_H + #define XKBCOMP_PARSER_PRIV_H + +-struct scanner; + struct parser_param; + ++#include "scanner-utils.h" + #include "parser.h" + + int +-scanner_error(struct scanner *scanner, const char *msg); +- +-void +-scanner_warn(struct scanner *s, const char *msg); +- +-int + _xkbcommon_lex(YYSTYPE *yylval, struct scanner *scanner); + + XkbFile * +-parse(struct xkb_context *ctx, void *scanner, const char *map); ++parse(struct xkb_context *ctx, struct scanner *scanner, const char *map); + + int +-keyword_to_token(const char *string); ++keyword_to_token(const char *string, unsigned int len); + + #endif +--- a/src/3rdparty/xkbcommon/src/xkbcomp/parser.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/parser.c +@@ -82,27 +82,21 @@ + + struct parser_param { + struct xkb_context *ctx; +- void *scanner; ++ struct scanner *scanner; + XkbFile *rtrn; + bool more_maps; + }; + +-static void +-parser_error(struct parser_param *param, const char *msg) +-{ +- scanner_error(param->scanner, msg); +-} ++#define parser_err(param, fmt, ...) \ ++ scanner_err((param)->scanner, fmt, ##__VA_ARGS__) + +-static void +-parser_warn(struct parser_param *param, const char *msg) +-{ +- scanner_warn(param->scanner, msg); +-} ++#define parser_warn(param, fmt, ...) \ ++ scanner_warn((param)->scanner, fmt, ##__VA_ARGS__) + + static void + _xkbcommon_error(struct parser_param *param, const char *msg) + { +- parser_error(param, msg); ++ parser_err(param, "%s", msg); + } + + static bool +@@ -129,11 +123,11 @@ resolve_keysym(const char *str, xkb_keys + return false; + } + +-#define scanner param->scanner ++#define param_scanner param->scanner + + + /* Line 268 of yacc.c */ +-#line 137 "src/xkbcomp/parser.c" ++#line 131 "src/xkbcomp/parser.c" + + /* Enabling traces. */ + #ifndef YYDEBUG +@@ -298,7 +292,7 @@ typedef union YYSTYPE + { + + /* Line 293 of yacc.c */ +-#line 167 "parser.y" ++#line 161 "parser.y" + + int ival; + int64_t num; +@@ -327,7 +321,7 @@ typedef union YYSTYPE + + + /* Line 293 of yacc.c */ +-#line 331 "src/xkbcomp/parser.c" ++#line 325 "src/xkbcomp/parser.c" + } YYSTYPE; + # define YYSTYPE_IS_TRIVIAL 1 + # define yystype YYSTYPE /* obsolescent; will be withdrawn */ +@@ -339,7 +333,7 @@ typedef union YYSTYPE + + + /* Line 343 of yacc.c */ +-#line 343 "src/xkbcomp/parser.c" ++#line 337 "src/xkbcomp/parser.c" + + #ifdef short + # undef short +@@ -698,25 +692,25 @@ static const yytype_int16 yyrhs[] = + /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ + static const yytype_uint16 yyrline[] = + { +- 0, 238, 238, 240, 242, 246, 252, 253, 254, 257, +- 264, 268, 283, 284, 285, 286, 287, 290, 291, 294, +- 295, 298, 299, 300, 301, 302, 303, 304, 305, 308, +- 310, 313, 318, 323, 328, 333, 338, 343, 348, 353, +- 358, 363, 368, 369, 370, 371, 378, 380, 382, 386, +- 390, 394, 398, 400, 404, 406, 410, 416, 418, 422, +- 424, 428, 434, 440, 442, 444, 447, 448, 449, 450, +- 451, 454, 456, 460, 464, 468, 472, 474, 478, 480, +- 484, 488, 489, 492, 494, 496, 498, 500, 504, 505, +- 508, 509, 513, 514, 517, 519, 523, 527, 528, 531, +- 534, 536, 540, 542, 544, 548, 550, 554, 558, 562, +- 563, 564, 565, 568, 569, 572, 574, 576, 578, 580, +- 582, 584, 586, 588, 590, 592, 596, 597, 600, 601, +- 602, 603, 604, 614, 615, 618, 620, 624, 626, 628, +- 630, 632, 634, 638, 640, 642, 644, 646, 648, 650, +- 652, 656, 658, 662, 666, 668, 670, 672, 676, 678, ++ 0, 232, 232, 234, 236, 240, 246, 247, 248, 251, ++ 259, 263, 278, 279, 280, 281, 282, 285, 286, 289, ++ 290, 293, 294, 295, 296, 297, 298, 299, 300, 303, ++ 305, 308, 313, 318, 323, 328, 333, 338, 343, 348, ++ 353, 358, 363, 364, 365, 366, 373, 375, 377, 381, ++ 385, 389, 393, 396, 400, 402, 406, 412, 414, 418, ++ 421, 425, 431, 437, 440, 442, 445, 446, 447, 448, ++ 449, 452, 454, 458, 462, 466, 470, 472, 476, 478, ++ 482, 486, 487, 490, 492, 494, 496, 498, 502, 503, ++ 506, 507, 511, 512, 515, 517, 521, 525, 526, 529, ++ 532, 534, 538, 540, 542, 546, 548, 552, 556, 560, ++ 561, 562, 563, 566, 567, 570, 572, 574, 576, 578, ++ 580, 582, 584, 586, 588, 590, 594, 595, 598, 599, ++ 600, 601, 602, 612, 613, 616, 619, 623, 625, 627, ++ 629, 631, 633, 637, 639, 641, 643, 645, 647, 649, ++ 651, 655, 658, 662, 666, 668, 670, 672, 676, 678, + 680, 682, 686, 687, 690, 692, 694, 696, 700, 704, +- 710, 711, 725, 726, 729, 730, 733, 736, 739, 742, +- 743, 746, 749, 750, 753 ++ 710, 711, 731, 732, 735, 736, 739, 742, 745, 748, ++ 749, 752, 755, 756, 759 + }; + #endif + +@@ -1217,7 +1211,7 @@ while (YYID (0)) + #ifdef YYLEX_PARAM + # define YYLEX yylex (&yylval, YYLEX_PARAM) + #else +-# define YYLEX yylex (&yylval, scanner) ++# define YYLEX yylex (&yylval, param_scanner) + #endif + + /* Enable debugging if requested. */ +@@ -1970,75 +1964,76 @@ yyreduce: + case 2: + + /* Line 1806 of yacc.c */ +-#line 239 "parser.y" ++#line 233 "parser.y" + { (yyval.file) = param->rtrn = (yyvsp[(1) - (1)].file); param->more_maps = true; } + break; + + case 3: + + /* Line 1806 of yacc.c */ +-#line 241 "parser.y" ++#line 235 "parser.y" + { (yyval.file) = param->rtrn = (yyvsp[(1) - (1)].file); param->more_maps = true; YYACCEPT; } + break; + + case 4: + + /* Line 1806 of yacc.c */ +-#line 243 "parser.y" ++#line 237 "parser.y" + { (yyval.file) = param->rtrn = NULL; param->more_maps = false; } + break; + + case 5: + + /* Line 1806 of yacc.c */ +-#line 249 "parser.y" +- { (yyval.file) = XkbFileCreate(param->ctx, (yyvsp[(2) - (7)].file_type), (yyvsp[(3) - (7)].str), &(yyvsp[(5) - (7)].file)->common, (yyvsp[(1) - (7)].mapFlags)); } ++#line 243 "parser.y" ++ { (yyval.file) = XkbFileCreate((yyvsp[(2) - (7)].file_type), (yyvsp[(3) - (7)].str), (ParseCommon *) (yyvsp[(5) - (7)].file), (yyvsp[(1) - (7)].mapFlags)); } + break; + + case 6: + + /* Line 1806 of yacc.c */ +-#line 252 "parser.y" ++#line 246 "parser.y" + { (yyval.file_type) = FILE_TYPE_KEYMAP; } + break; + + case 7: + + /* Line 1806 of yacc.c */ +-#line 253 "parser.y" ++#line 247 "parser.y" + { (yyval.file_type) = FILE_TYPE_KEYMAP; } + break; + + case 8: + + /* Line 1806 of yacc.c */ +-#line 254 "parser.y" ++#line 248 "parser.y" + { (yyval.file_type) = FILE_TYPE_KEYMAP; } + break; + + case 9: + + /* Line 1806 of yacc.c */ +-#line 258 "parser.y" ++#line 252 "parser.y" + { + if (!(yyvsp[(2) - (2)].file)) + (yyval.file) = (yyvsp[(1) - (2)].file); + else +- (yyval.file) = (XkbFile *)AppendStmt(&(yyvsp[(1) - (2)].file)->common, &(yyvsp[(2) - (2)].file)->common); ++ (yyval.file) = (XkbFile *) AppendStmt((ParseCommon *) (yyvsp[(1) - (2)].file), ++ (ParseCommon *) (yyvsp[(2) - (2)].file)); + } + break; + + case 10: + + /* Line 1806 of yacc.c */ +-#line 265 "parser.y" ++#line 260 "parser.y" + { (yyval.file) = (yyvsp[(1) - (1)].file); } + break; + + case 11: + + /* Line 1806 of yacc.c */ +-#line 271 "parser.y" ++#line 266 "parser.y" + { + if ((yyvsp[(2) - (7)].file_type) == FILE_TYPE_GEOMETRY) { + free((yyvsp[(3) - (7)].str)); +@@ -2046,7 +2041,7 @@ yyreduce: + (yyval.file) = NULL; + } + else { +- (yyval.file) = XkbFileCreate(param->ctx, (yyvsp[(2) - (7)].file_type), (yyvsp[(3) - (7)].str), (yyvsp[(5) - (7)].any), (yyvsp[(1) - (7)].mapFlags)); ++ (yyval.file) = XkbFileCreate((yyvsp[(2) - (7)].file_type), (yyvsp[(3) - (7)].str), (yyvsp[(5) - (7)].any), (yyvsp[(1) - (7)].mapFlags)); + } + } + break; +@@ -2054,273 +2049,273 @@ yyreduce: + case 12: + + /* Line 1806 of yacc.c */ +-#line 283 "parser.y" ++#line 278 "parser.y" + { (yyval.file_type) = FILE_TYPE_KEYCODES; } + break; + + case 13: + + /* Line 1806 of yacc.c */ +-#line 284 "parser.y" ++#line 279 "parser.y" + { (yyval.file_type) = FILE_TYPE_TYPES; } + break; + + case 14: + + /* Line 1806 of yacc.c */ +-#line 285 "parser.y" ++#line 280 "parser.y" + { (yyval.file_type) = FILE_TYPE_COMPAT; } + break; + + case 15: + + /* Line 1806 of yacc.c */ +-#line 286 "parser.y" ++#line 281 "parser.y" + { (yyval.file_type) = FILE_TYPE_SYMBOLS; } + break; + + case 16: + + /* Line 1806 of yacc.c */ +-#line 287 "parser.y" ++#line 282 "parser.y" + { (yyval.file_type) = FILE_TYPE_GEOMETRY; } + break; + + case 17: + + /* Line 1806 of yacc.c */ +-#line 290 "parser.y" ++#line 285 "parser.y" + { (yyval.mapFlags) = (yyvsp[(1) - (1)].mapFlags); } + break; + + case 18: + + /* Line 1806 of yacc.c */ +-#line 291 "parser.y" ++#line 286 "parser.y" + { (yyval.mapFlags) = 0; } + break; + + case 19: + + /* Line 1806 of yacc.c */ +-#line 294 "parser.y" ++#line 289 "parser.y" + { (yyval.mapFlags) = ((yyvsp[(1) - (2)].mapFlags) | (yyvsp[(2) - (2)].mapFlags)); } + break; + + case 20: + + /* Line 1806 of yacc.c */ +-#line 295 "parser.y" ++#line 290 "parser.y" + { (yyval.mapFlags) = (yyvsp[(1) - (1)].mapFlags); } + break; + + case 21: + + /* Line 1806 of yacc.c */ +-#line 298 "parser.y" ++#line 293 "parser.y" + { (yyval.mapFlags) = MAP_IS_PARTIAL; } + break; + + case 22: + + /* Line 1806 of yacc.c */ +-#line 299 "parser.y" ++#line 294 "parser.y" + { (yyval.mapFlags) = MAP_IS_DEFAULT; } + break; + + case 23: + + /* Line 1806 of yacc.c */ +-#line 300 "parser.y" ++#line 295 "parser.y" + { (yyval.mapFlags) = MAP_IS_HIDDEN; } + break; + + case 24: + + /* Line 1806 of yacc.c */ +-#line 301 "parser.y" ++#line 296 "parser.y" + { (yyval.mapFlags) = MAP_HAS_ALPHANUMERIC; } + break; + + case 25: + + /* Line 1806 of yacc.c */ +-#line 302 "parser.y" ++#line 297 "parser.y" + { (yyval.mapFlags) = MAP_HAS_MODIFIER; } + break; + + case 26: + + /* Line 1806 of yacc.c */ +-#line 303 "parser.y" ++#line 298 "parser.y" + { (yyval.mapFlags) = MAP_HAS_KEYPAD; } + break; + + case 27: + + /* Line 1806 of yacc.c */ +-#line 304 "parser.y" ++#line 299 "parser.y" + { (yyval.mapFlags) = MAP_HAS_FN; } + break; + + case 28: + + /* Line 1806 of yacc.c */ +-#line 305 "parser.y" ++#line 300 "parser.y" + { (yyval.mapFlags) = MAP_IS_ALTGR; } + break; + + case 29: + + /* Line 1806 of yacc.c */ +-#line 309 "parser.y" ++#line 304 "parser.y" + { (yyval.any) = AppendStmt((yyvsp[(1) - (2)].any), (yyvsp[(2) - (2)].any)); } + break; + + case 30: + + /* Line 1806 of yacc.c */ +-#line 310 "parser.y" ++#line 305 "parser.y" + { (yyval.any) = NULL; } + break; + + case 31: + + /* Line 1806 of yacc.c */ +-#line 314 "parser.y" ++#line 309 "parser.y" + { + (yyvsp[(2) - (2)].var)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].var)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].var); + } + break; + + case 32: + + /* Line 1806 of yacc.c */ +-#line 319 "parser.y" ++#line 314 "parser.y" + { + (yyvsp[(2) - (2)].vmod)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].vmod)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].vmod); + } + break; + + case 33: + + /* Line 1806 of yacc.c */ +-#line 324 "parser.y" ++#line 319 "parser.y" + { + (yyvsp[(2) - (2)].interp)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].interp)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].interp); + } + break; + + case 34: + + /* Line 1806 of yacc.c */ +-#line 329 "parser.y" ++#line 324 "parser.y" + { + (yyvsp[(2) - (2)].keyCode)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].keyCode)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].keyCode); + } + break; + + case 35: + + /* Line 1806 of yacc.c */ +-#line 334 "parser.y" ++#line 329 "parser.y" + { + (yyvsp[(2) - (2)].keyAlias)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].keyAlias)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].keyAlias); + } + break; + + case 36: + + /* Line 1806 of yacc.c */ +-#line 339 "parser.y" ++#line 334 "parser.y" + { + (yyvsp[(2) - (2)].keyType)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].keyType)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].keyType); + } + break; + + case 37: + + /* Line 1806 of yacc.c */ +-#line 344 "parser.y" ++#line 339 "parser.y" + { + (yyvsp[(2) - (2)].syms)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].syms)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].syms); + } + break; + + case 38: + + /* Line 1806 of yacc.c */ +-#line 349 "parser.y" ++#line 344 "parser.y" + { + (yyvsp[(2) - (2)].modMask)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].modMask)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].modMask); + } + break; + + case 39: + + /* Line 1806 of yacc.c */ +-#line 354 "parser.y" ++#line 349 "parser.y" + { + (yyvsp[(2) - (2)].groupCompat)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].groupCompat)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].groupCompat); + } + break; + + case 40: + + /* Line 1806 of yacc.c */ +-#line 359 "parser.y" ++#line 354 "parser.y" + { + (yyvsp[(2) - (2)].ledMap)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].ledMap)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].ledMap); + } + break; + + case 41: + + /* Line 1806 of yacc.c */ +-#line 364 "parser.y" ++#line 359 "parser.y" + { + (yyvsp[(2) - (2)].ledName)->merge = (yyvsp[(1) - (2)].merge); +- (yyval.any) = &(yyvsp[(2) - (2)].ledName)->common; ++ (yyval.any) = (ParseCommon *) (yyvsp[(2) - (2)].ledName); + } + break; + + case 42: + + /* Line 1806 of yacc.c */ +-#line 368 "parser.y" ++#line 363 "parser.y" + { (yyval.any) = NULL; } + break; + + case 43: + + /* Line 1806 of yacc.c */ +-#line 369 "parser.y" ++#line 364 "parser.y" + { (yyval.any) = NULL; } + break; + + case 44: + + /* Line 1806 of yacc.c */ +-#line 370 "parser.y" ++#line 365 "parser.y" + { (yyval.any) = NULL; } + break; + + case 45: + + /* Line 1806 of yacc.c */ +-#line 372 "parser.y" ++#line 367 "parser.y" + { +- (yyval.any) = &IncludeCreate(param->ctx, (yyvsp[(2) - (2)].str), (yyvsp[(1) - (2)].merge))->common; ++ (yyval.any) = (ParseCommon *) IncludeCreate(param->ctx, (yyvsp[(2) - (2)].str), (yyvsp[(1) - (2)].merge)); + free((yyvsp[(2) - (2)].str)); + } + break; +@@ -2328,609 +2323,612 @@ yyreduce: + case 46: + + /* Line 1806 of yacc.c */ +-#line 379 "parser.y" ++#line 374 "parser.y" + { (yyval.var) = VarCreate((yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr)); } + break; + + case 47: + + /* Line 1806 of yacc.c */ +-#line 381 "parser.y" ++#line 376 "parser.y" + { (yyval.var) = BoolVarCreate((yyvsp[(1) - (2)].sval), true); } + break; + + case 48: + + /* Line 1806 of yacc.c */ +-#line 383 "parser.y" ++#line 378 "parser.y" + { (yyval.var) = BoolVarCreate((yyvsp[(2) - (3)].sval), false); } + break; + + case 49: + + /* Line 1806 of yacc.c */ +-#line 387 "parser.y" ++#line 382 "parser.y" + { (yyval.keyCode) = KeycodeCreate((yyvsp[(1) - (4)].sval), (yyvsp[(3) - (4)].num)); } + break; + + case 50: + + /* Line 1806 of yacc.c */ +-#line 391 "parser.y" ++#line 386 "parser.y" + { (yyval.keyAlias) = KeyAliasCreate((yyvsp[(2) - (5)].sval), (yyvsp[(4) - (5)].sval)); } + break; + + case 51: + + /* Line 1806 of yacc.c */ +-#line 395 "parser.y" ++#line 390 "parser.y" + { (yyval.vmod) = (yyvsp[(2) - (3)].vmod); } + break; + + case 52: + + /* Line 1806 of yacc.c */ +-#line 399 "parser.y" +- { (yyval.vmod) = (VModDef *)AppendStmt(&(yyvsp[(1) - (3)].vmod)->common, &(yyvsp[(3) - (3)].vmod)->common); } ++#line 394 "parser.y" ++ { (yyval.vmod) = (VModDef *) AppendStmt((ParseCommon *) (yyvsp[(1) - (3)].vmod), ++ (ParseCommon *) (yyvsp[(3) - (3)].vmod)); } + break; + + case 53: + + /* Line 1806 of yacc.c */ +-#line 401 "parser.y" ++#line 397 "parser.y" + { (yyval.vmod) = (yyvsp[(1) - (1)].vmod); } + break; + + case 54: + + /* Line 1806 of yacc.c */ +-#line 405 "parser.y" ++#line 401 "parser.y" + { (yyval.vmod) = VModCreate((yyvsp[(1) - (1)].sval), NULL); } + break; + + case 55: + + /* Line 1806 of yacc.c */ +-#line 407 "parser.y" ++#line 403 "parser.y" + { (yyval.vmod) = VModCreate((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].expr)); } + break; + + case 56: + + /* Line 1806 of yacc.c */ +-#line 413 "parser.y" ++#line 409 "parser.y" + { (yyvsp[(2) - (6)].interp)->def = (yyvsp[(4) - (6)].var); (yyval.interp) = (yyvsp[(2) - (6)].interp); } + break; + + case 57: + + /* Line 1806 of yacc.c */ +-#line 417 "parser.y" ++#line 413 "parser.y" + { (yyval.interp) = InterpCreate((yyvsp[(1) - (3)].keysym), (yyvsp[(3) - (3)].expr)); } + break; + + case 58: + + /* Line 1806 of yacc.c */ +-#line 419 "parser.y" ++#line 415 "parser.y" + { (yyval.interp) = InterpCreate((yyvsp[(1) - (1)].keysym), NULL); } + break; + + case 59: + + /* Line 1806 of yacc.c */ +-#line 423 "parser.y" +- { (yyval.var) = (VarDef *)AppendStmt(&(yyvsp[(1) - (2)].var)->common, &(yyvsp[(2) - (2)].var)->common); } ++#line 419 "parser.y" ++ { (yyval.var) = (VarDef *) AppendStmt((ParseCommon *) (yyvsp[(1) - (2)].var), ++ (ParseCommon *) (yyvsp[(2) - (2)].var)); } + break; + + case 60: + + /* Line 1806 of yacc.c */ +-#line 425 "parser.y" ++#line 422 "parser.y" + { (yyval.var) = (yyvsp[(1) - (1)].var); } + break; + + case 61: + + /* Line 1806 of yacc.c */ +-#line 431 "parser.y" ++#line 428 "parser.y" + { (yyval.keyType) = KeyTypeCreate((yyvsp[(2) - (6)].sval), (yyvsp[(4) - (6)].var)); } + break; + + case 62: + + /* Line 1806 of yacc.c */ +-#line 437 "parser.y" ++#line 434 "parser.y" + { (yyval.syms) = SymbolsCreate((yyvsp[(2) - (6)].sval), (yyvsp[(4) - (6)].var)); } + break; + + case 63: + + /* Line 1806 of yacc.c */ +-#line 441 "parser.y" +- { (yyval.var) = (VarDef *)AppendStmt(&(yyvsp[(1) - (3)].var)->common, &(yyvsp[(3) - (3)].var)->common); } ++#line 438 "parser.y" ++ { (yyval.var) = (VarDef *) AppendStmt((ParseCommon *) (yyvsp[(1) - (3)].var), ++ (ParseCommon *) (yyvsp[(3) - (3)].var)); } + break; + + case 64: + + /* Line 1806 of yacc.c */ +-#line 443 "parser.y" ++#line 441 "parser.y" + { (yyval.var) = (yyvsp[(1) - (1)].var); } + break; + + case 65: + + /* Line 1806 of yacc.c */ +-#line 444 "parser.y" ++#line 442 "parser.y" + { (yyval.var) = NULL; } + break; + + case 66: + + /* Line 1806 of yacc.c */ +-#line 447 "parser.y" ++#line 445 "parser.y" + { (yyval.var) = VarCreate((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 67: + + /* Line 1806 of yacc.c */ +-#line 448 "parser.y" ++#line 446 "parser.y" + { (yyval.var) = VarCreate((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 68: + + /* Line 1806 of yacc.c */ +-#line 449 "parser.y" ++#line 447 "parser.y" + { (yyval.var) = BoolVarCreate((yyvsp[(1) - (1)].sval), true); } + break; + + case 69: + + /* Line 1806 of yacc.c */ +-#line 450 "parser.y" ++#line 448 "parser.y" + { (yyval.var) = BoolVarCreate((yyvsp[(2) - (2)].sval), false); } + break; + + case 70: + + /* Line 1806 of yacc.c */ +-#line 451 "parser.y" ++#line 449 "parser.y" + { (yyval.var) = VarCreate(NULL, (yyvsp[(1) - (1)].expr)); } + break; + + case 71: + + /* Line 1806 of yacc.c */ +-#line 455 "parser.y" ++#line 453 "parser.y" + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } + break; + + case 72: + + /* Line 1806 of yacc.c */ +-#line 457 "parser.y" ++#line 455 "parser.y" + { (yyval.expr) = ExprCreateUnary(EXPR_ACTION_LIST, EXPR_TYPE_ACTION, (yyvsp[(2) - (3)].expr)); } + break; + + case 73: + + /* Line 1806 of yacc.c */ +-#line 461 "parser.y" ++#line 459 "parser.y" + { (yyval.groupCompat) = GroupCompatCreate((yyvsp[(2) - (5)].ival), (yyvsp[(4) - (5)].expr)); } + break; + + case 74: + + /* Line 1806 of yacc.c */ +-#line 465 "parser.y" ++#line 463 "parser.y" + { (yyval.modMask) = ModMapCreate((yyvsp[(2) - (6)].sval), (yyvsp[(4) - (6)].expr)); } + break; + + case 75: + + /* Line 1806 of yacc.c */ +-#line 469 "parser.y" ++#line 467 "parser.y" + { (yyval.ledMap) = LedMapCreate((yyvsp[(2) - (6)].sval), (yyvsp[(4) - (6)].var)); } + break; + + case 76: + + /* Line 1806 of yacc.c */ +-#line 473 "parser.y" ++#line 471 "parser.y" + { (yyval.ledName) = LedNameCreate((yyvsp[(2) - (5)].ival), (yyvsp[(4) - (5)].expr), false); } + break; + + case 77: + + /* Line 1806 of yacc.c */ +-#line 475 "parser.y" ++#line 473 "parser.y" + { (yyval.ledName) = LedNameCreate((yyvsp[(3) - (6)].ival), (yyvsp[(5) - (6)].expr), true); } + break; + + case 78: + + /* Line 1806 of yacc.c */ +-#line 479 "parser.y" ++#line 477 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 79: + + /* Line 1806 of yacc.c */ +-#line 481 "parser.y" ++#line 479 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 80: + + /* Line 1806 of yacc.c */ +-#line 485 "parser.y" ++#line 483 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 81: + + /* Line 1806 of yacc.c */ +-#line 488 "parser.y" ++#line 486 "parser.y" + { (yyval.geom) = NULL;} + break; + + case 82: + + /* Line 1806 of yacc.c */ +-#line 489 "parser.y" ++#line 487 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 83: + + /* Line 1806 of yacc.c */ +-#line 493 "parser.y" ++#line 491 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 84: + + /* Line 1806 of yacc.c */ +-#line 495 "parser.y" +- { FreeStmt(&(yyvsp[(1) - (1)].var)->common); (yyval.geom) = NULL; } ++#line 493 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(1) - (1)].var)); (yyval.geom) = NULL; } + break; + + case 85: + + /* Line 1806 of yacc.c */ +-#line 497 "parser.y" ++#line 495 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 86: + + /* Line 1806 of yacc.c */ +-#line 499 "parser.y" +- { FreeStmt(&(yyvsp[(1) - (1)].ledMap)->common); (yyval.geom) = NULL; } ++#line 497 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(1) - (1)].ledMap)); (yyval.geom) = NULL; } + break; + + case 87: + + /* Line 1806 of yacc.c */ +-#line 501 "parser.y" ++#line 499 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 88: + + /* Line 1806 of yacc.c */ +-#line 504 "parser.y" ++#line 502 "parser.y" + { (yyval.geom) = NULL;} + break; + + case 89: + + /* Line 1806 of yacc.c */ +-#line 505 "parser.y" ++#line 503 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 90: + + /* Line 1806 of yacc.c */ +-#line 508 "parser.y" ++#line 506 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 91: + + /* Line 1806 of yacc.c */ +-#line 510 "parser.y" +- { FreeStmt(&(yyvsp[(1) - (1)].var)->common); (yyval.geom) = NULL; } ++#line 508 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(1) - (1)].var)); (yyval.geom) = NULL; } + break; + + case 92: + + /* Line 1806 of yacc.c */ +-#line 513 "parser.y" ++#line 511 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 93: + + /* Line 1806 of yacc.c */ +-#line 514 "parser.y" ++#line 512 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 94: + + /* Line 1806 of yacc.c */ +-#line 518 "parser.y" ++#line 516 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 95: + + /* Line 1806 of yacc.c */ +-#line 520 "parser.y" +- { FreeStmt(&(yyvsp[(2) - (3)].expr)->common); (yyval.geom) = NULL; } ++#line 518 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(2) - (3)].expr)); (yyval.geom) = NULL; } + break; + + case 96: + + /* Line 1806 of yacc.c */ +-#line 524 "parser.y" ++#line 522 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 97: + + /* Line 1806 of yacc.c */ +-#line 527 "parser.y" ++#line 525 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 98: + + /* Line 1806 of yacc.c */ +-#line 528 "parser.y" ++#line 526 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 99: + + /* Line 1806 of yacc.c */ +-#line 531 "parser.y" ++#line 529 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 100: + + /* Line 1806 of yacc.c */ +-#line 535 "parser.y" ++#line 533 "parser.y" + { (yyval.geom) = NULL;} + break; + + case 101: + + /* Line 1806 of yacc.c */ +-#line 537 "parser.y" ++#line 535 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 102: + + /* Line 1806 of yacc.c */ +-#line 541 "parser.y" ++#line 539 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 103: + + /* Line 1806 of yacc.c */ +-#line 543 "parser.y" ++#line 541 "parser.y" + { (yyval.geom) = NULL; } + break; + + case 104: + + /* Line 1806 of yacc.c */ +-#line 545 "parser.y" +- { FreeStmt(&(yyvsp[(3) - (3)].expr)->common); (yyval.geom) = NULL; } ++#line 543 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(3) - (3)].expr)); (yyval.geom) = NULL; } + break; + + case 105: + + /* Line 1806 of yacc.c */ +-#line 549 "parser.y" ++#line 547 "parser.y" + { (yyval.expr) = NULL; } + break; + + case 106: + + /* Line 1806 of yacc.c */ +-#line 551 "parser.y" ++#line 549 "parser.y" + { (yyval.expr) = NULL; } + break; + + case 107: + + /* Line 1806 of yacc.c */ +-#line 555 "parser.y" ++#line 553 "parser.y" + { (yyval.expr) = NULL; } + break; + + case 108: + + /* Line 1806 of yacc.c */ +-#line 559 "parser.y" +- { FreeStmt(&(yyvsp[(4) - (6)].var)->common); (yyval.geom) = NULL; } ++#line 557 "parser.y" ++ { FreeStmt((ParseCommon *) (yyvsp[(4) - (6)].var)); (yyval.geom) = NULL; } + break; + + case 109: + + /* Line 1806 of yacc.c */ +-#line 562 "parser.y" ++#line 560 "parser.y" + { (yyval.ival) = 0; } + break; + + case 110: + + /* Line 1806 of yacc.c */ +-#line 563 "parser.y" ++#line 561 "parser.y" + { (yyval.ival) = 0; } + break; + + case 111: + + /* Line 1806 of yacc.c */ +-#line 564 "parser.y" ++#line 562 "parser.y" + { (yyval.ival) = 0; } + break; + + case 112: + + /* Line 1806 of yacc.c */ +-#line 565 "parser.y" ++#line 563 "parser.y" + { (yyval.ival) = 0; } + break; + + case 113: + + /* Line 1806 of yacc.c */ +-#line 568 "parser.y" ++#line 566 "parser.y" + { (yyval.sval) = (yyvsp[(1) - (1)].sval); } + break; + + case 114: + + /* Line 1806 of yacc.c */ +-#line 569 "parser.y" ++#line 567 "parser.y" + { (yyval.sval) = (yyvsp[(1) - (1)].sval); } + break; + + case 115: + + /* Line 1806 of yacc.c */ +-#line 573 "parser.y" ++#line 571 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "action"); } + break; + + case 116: + + /* Line 1806 of yacc.c */ +-#line 575 "parser.y" ++#line 573 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "interpret"); } + break; + + case 117: + + /* Line 1806 of yacc.c */ +-#line 577 "parser.y" ++#line 575 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "type"); } + break; + + case 118: + + /* Line 1806 of yacc.c */ +-#line 579 "parser.y" ++#line 577 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "key"); } + break; + + case 119: + + /* Line 1806 of yacc.c */ +-#line 581 "parser.y" ++#line 579 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "group"); } + break; + + case 120: + + /* Line 1806 of yacc.c */ +-#line 583 "parser.y" ++#line 581 "parser.y" + {(yyval.sval) = xkb_atom_intern_literal(param->ctx, "modifier_map");} + break; + + case 121: + + /* Line 1806 of yacc.c */ +-#line 585 "parser.y" ++#line 583 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "indicator"); } + break; + + case 122: + + /* Line 1806 of yacc.c */ +-#line 587 "parser.y" ++#line 585 "parser.y" + { (yyval.sval) = XKB_ATOM_NONE; } + break; + + case 123: + + /* Line 1806 of yacc.c */ +-#line 589 "parser.y" ++#line 587 "parser.y" + { (yyval.sval) = XKB_ATOM_NONE; } + break; + + case 124: + + /* Line 1806 of yacc.c */ +-#line 591 "parser.y" ++#line 589 "parser.y" + { (yyval.sval) = XKB_ATOM_NONE; } + break; + + case 125: + + /* Line 1806 of yacc.c */ +-#line 593 "parser.y" ++#line 591 "parser.y" + { (yyval.sval) = XKB_ATOM_NONE; } + break; + + case 126: + + /* Line 1806 of yacc.c */ +-#line 596 "parser.y" ++#line 594 "parser.y" + { (yyval.merge) = (yyvsp[(1) - (1)].merge); } + break; + + case 127: + + /* Line 1806 of yacc.c */ +-#line 597 "parser.y" ++#line 595 "parser.y" + { (yyval.merge) = MERGE_DEFAULT; } + break; + + case 128: + + /* Line 1806 of yacc.c */ +-#line 600 "parser.y" ++#line 598 "parser.y" + { (yyval.merge) = MERGE_DEFAULT; } + break; + + case 129: + + /* Line 1806 of yacc.c */ +-#line 601 "parser.y" ++#line 599 "parser.y" + { (yyval.merge) = MERGE_AUGMENT; } + break; + + case 130: + + /* Line 1806 of yacc.c */ +-#line 602 "parser.y" ++#line 600 "parser.y" + { (yyval.merge) = MERGE_OVERRIDE; } + break; + + case 131: + + /* Line 1806 of yacc.c */ +-#line 603 "parser.y" ++#line 601 "parser.y" + { (yyval.merge) = MERGE_REPLACE; } + break; + + case 132: + + /* Line 1806 of yacc.c */ +-#line 605 "parser.y" ++#line 603 "parser.y" + { + /* + * This used to be MERGE_ALT_FORM. This functionality was +@@ -2943,134 +2941,136 @@ yyreduce: + case 133: + + /* Line 1806 of yacc.c */ +-#line 614 "parser.y" ++#line 612 "parser.y" + { (yyval.expr) = (yyvsp[(1) - (1)].expr); } + break; + + case 134: + + /* Line 1806 of yacc.c */ +-#line 615 "parser.y" ++#line 613 "parser.y" + { (yyval.expr) = NULL; } + break; + + case 135: + + /* Line 1806 of yacc.c */ +-#line 619 "parser.y" +- { (yyval.expr) = (ExprDef *)AppendStmt(&(yyvsp[(1) - (3)].expr)->common, &(yyvsp[(3) - (3)].expr)->common); } ++#line 617 "parser.y" ++ { (yyval.expr) = (ExprDef *) AppendStmt((ParseCommon *) (yyvsp[(1) - (3)].expr), ++ (ParseCommon *) (yyvsp[(3) - (3)].expr)); } + break; + + case 136: + + /* Line 1806 of yacc.c */ +-#line 621 "parser.y" ++#line 620 "parser.y" + { (yyval.expr) = (yyvsp[(1) - (1)].expr); } + break; + + case 137: + + /* Line 1806 of yacc.c */ +-#line 625 "parser.y" ++#line 624 "parser.y" + { (yyval.expr) = ExprCreateBinary(EXPR_DIVIDE, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 138: + + /* Line 1806 of yacc.c */ +-#line 627 "parser.y" ++#line 626 "parser.y" + { (yyval.expr) = ExprCreateBinary(EXPR_ADD, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 139: + + /* Line 1806 of yacc.c */ +-#line 629 "parser.y" ++#line 628 "parser.y" + { (yyval.expr) = ExprCreateBinary(EXPR_SUBTRACT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 140: + + /* Line 1806 of yacc.c */ +-#line 631 "parser.y" ++#line 630 "parser.y" + { (yyval.expr) = ExprCreateBinary(EXPR_MULTIPLY, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 141: + + /* Line 1806 of yacc.c */ +-#line 633 "parser.y" ++#line 632 "parser.y" + { (yyval.expr) = ExprCreateBinary(EXPR_ASSIGN, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 142: + + /* Line 1806 of yacc.c */ +-#line 635 "parser.y" ++#line 634 "parser.y" + { (yyval.expr) = (yyvsp[(1) - (1)].expr); } + break; + + case 143: + + /* Line 1806 of yacc.c */ +-#line 639 "parser.y" ++#line 638 "parser.y" + { (yyval.expr) = ExprCreateUnary(EXPR_NEGATE, (yyvsp[(2) - (2)].expr)->expr.value_type, (yyvsp[(2) - (2)].expr)); } + break; + + case 144: + + /* Line 1806 of yacc.c */ +-#line 641 "parser.y" ++#line 640 "parser.y" + { (yyval.expr) = ExprCreateUnary(EXPR_UNARY_PLUS, (yyvsp[(2) - (2)].expr)->expr.value_type, (yyvsp[(2) - (2)].expr)); } + break; + + case 145: + + /* Line 1806 of yacc.c */ +-#line 643 "parser.y" ++#line 642 "parser.y" + { (yyval.expr) = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, (yyvsp[(2) - (2)].expr)); } + break; + + case 146: + + /* Line 1806 of yacc.c */ +-#line 645 "parser.y" ++#line 644 "parser.y" + { (yyval.expr) = ExprCreateUnary(EXPR_INVERT, (yyvsp[(2) - (2)].expr)->expr.value_type, (yyvsp[(2) - (2)].expr)); } + break; + + case 147: + + /* Line 1806 of yacc.c */ +-#line 647 "parser.y" ++#line 646 "parser.y" + { (yyval.expr) = (yyvsp[(1) - (1)].expr); } + break; + + case 148: + + /* Line 1806 of yacc.c */ +-#line 649 "parser.y" ++#line 648 "parser.y" + { (yyval.expr) = ExprCreateAction((yyvsp[(1) - (4)].sval), (yyvsp[(3) - (4)].expr)); } + break; + + case 149: + + /* Line 1806 of yacc.c */ +-#line 651 "parser.y" ++#line 650 "parser.y" + { (yyval.expr) = (yyvsp[(1) - (1)].expr); } + break; + + case 150: + + /* Line 1806 of yacc.c */ +-#line 653 "parser.y" ++#line 652 "parser.y" + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } + break; + + case 151: + + /* Line 1806 of yacc.c */ +-#line 657 "parser.y" +- { (yyval.expr) = (ExprDef *)AppendStmt(&(yyvsp[(1) - (3)].expr)->common, &(yyvsp[(3) - (3)].expr)->common); } ++#line 656 "parser.y" ++ { (yyval.expr) = (ExprDef *) AppendStmt((ParseCommon *) (yyvsp[(1) - (3)].expr), ++ (ParseCommon *) (yyvsp[(3) - (3)].expr)); } + break; + + case 152: +@@ -3215,14 +3215,20 @@ yyreduce: + /* Line 1806 of yacc.c */ + #line 712 "parser.y" + { +- if ((yyvsp[(1) - (1)].ival) < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */ +- (yyval.keysym) = XKB_KEY_0 + (yyvsp[(1) - (1)].ival); ++ if ((yyvsp[(1) - (1)].ival) < 0) { ++ parser_warn(param, "unrecognized keysym"); ++ (yyval.keysym) = XKB_KEY_NoSymbol; ++ } ++ else if ((yyvsp[(1) - (1)].ival) < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */ ++ (yyval.keysym) = XKB_KEY_0 + (xkb_keysym_t) (yyvsp[(1) - (1)].ival); + } + else { + char buf[17]; + snprintf(buf, sizeof(buf), "0x%x", (yyvsp[(1) - (1)].ival)); +- if (!resolve_keysym(buf, &(yyval.keysym))) ++ if (!resolve_keysym(buf, &(yyval.keysym))) { + parser_warn(param, "unrecognized keysym"); ++ (yyval.keysym) = XKB_KEY_NoSymbol; ++ } + } + } + break; +@@ -3230,98 +3236,98 @@ yyreduce: + case 172: + + /* Line 1806 of yacc.c */ +-#line 725 "parser.y" ++#line 731 "parser.y" + { (yyval.ival) = -(yyvsp[(2) - (2)].ival); } + break; + + case 173: + + /* Line 1806 of yacc.c */ +-#line 726 "parser.y" ++#line 732 "parser.y" + { (yyval.ival) = (yyvsp[(1) - (1)].ival); } + break; + + case 174: + + /* Line 1806 of yacc.c */ +-#line 729 "parser.y" ++#line 735 "parser.y" + { (yyval.ival) = (yyvsp[(1) - (1)].num); } + break; + + case 175: + + /* Line 1806 of yacc.c */ +-#line 730 "parser.y" ++#line 736 "parser.y" + { (yyval.ival) = (yyvsp[(1) - (1)].num); } + break; + + case 176: + + /* Line 1806 of yacc.c */ +-#line 733 "parser.y" ++#line 739 "parser.y" + { (yyval.ival) = 0; } + break; + + case 177: + + /* Line 1806 of yacc.c */ +-#line 736 "parser.y" ++#line 742 "parser.y" + { (yyval.ival) = (yyvsp[(1) - (1)].num); } + break; + + case 178: + + /* Line 1806 of yacc.c */ +-#line 739 "parser.y" ++#line 745 "parser.y" + { (yyval.num) = (yyvsp[(1) - (1)].num); } + break; + + case 179: + + /* Line 1806 of yacc.c */ +-#line 742 "parser.y" ++#line 748 "parser.y" + { (yyval.sval) = xkb_atom_steal(param->ctx, (yyvsp[(1) - (1)].str)); } + break; + + case 180: + + /* Line 1806 of yacc.c */ +-#line 743 "parser.y" ++#line 749 "parser.y" + { (yyval.sval) = xkb_atom_intern_literal(param->ctx, "default"); } + break; + + case 181: + + /* Line 1806 of yacc.c */ +-#line 746 "parser.y" ++#line 752 "parser.y" + { (yyval.sval) = xkb_atom_steal(param->ctx, (yyvsp[(1) - (1)].str)); } + break; + + case 182: + + /* Line 1806 of yacc.c */ +-#line 749 "parser.y" ++#line 755 "parser.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); } + break; + + case 183: + + /* Line 1806 of yacc.c */ +-#line 750 "parser.y" ++#line 756 "parser.y" + { (yyval.str) = NULL; } + break; + + case 184: + + /* Line 1806 of yacc.c */ +-#line 753 "parser.y" ++#line 759 "parser.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); } + break; + + + + /* Line 1806 of yacc.c */ +-#line 3325 "src/xkbcomp/parser.c" ++#line 3331 "src/xkbcomp/parser.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires +@@ -3552,13 +3558,11 @@ yyreturn: + + + /* Line 2067 of yacc.c */ +-#line 756 "parser.y" ++#line 762 "parser.y" + + +-#undef scanner +- + XkbFile * +-parse(struct xkb_context *ctx, void *scanner, const char *map) ++parse(struct xkb_context *ctx, struct scanner *scanner, const char *map) + { + int ret; + XkbFile *first = NULL; +@@ -3604,5 +3608,3 @@ parse(struct xkb_context *ctx, void *sca + return first; + } + +-#define scanner param->scanner +- +--- a/src/3rdparty/xkbcommon/src/xkbcomp/parser.h ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/parser.h +@@ -175,7 +175,7 @@ typedef union YYSTYPE + { + + /* Line 2068 of yacc.c */ +-#line 167 "parser.y" ++#line 161 "parser.y" + + int ival; + int64_t num; +--- a/src/3rdparty/xkbcommon/src/xkbcomp/rules.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/rules.c +@@ -52,84 +52,6 @@ + #include "include.h" + #include "scanner-utils.h" + +-/* +- * The rules file +- * ============== +- * The purpose of this file is to map between configuration values that +- * are easy for a user to specify and understand, and the configuration +- * values xkbcomp uses and understands. +- * xkbcomp uses the xkb_component_names struct, which maps directly to +- * include statements of the appropriate sections, called for short +- * KcCGST (see keycodes.c, types.c, compat.c, symbols.c; geometry.c was +- * removed). These are not really intuitive or straight-forward for +- * the uninitiated. +- * Instead, the user passes in a xkb_rule_names struct, which consists +- * of the name of a rules file (in Linux this is usually "evdev"), a +- * keyboard model (e.g. "pc105"), a set of layouts (which will end up +- * in different groups, e.g. "us,fr"), variants (used to alter/augment +- * the respective layout, e.g. "intl,dvorak"), and a set of options +- * (used to tweak some general behavior of the keyboard, e.g. +- * "ctrl:nocaps,compose:menu" to make the Caps Lock key act like Ctrl +- * and the Menu key like Compose). We call these RMLVO. +- * +- * Format of the file +- * ------------------ +- * The file consists of rule sets, each consisting of rules (one per +- * line), which match the MLVO values on the left hand side, and, if +- * the values match to the values the user passed in, results in the +- * values on the right hand side being added to the resulting KcCGST. +- * Since some values are related and repeated often, it is possible +- * to group them together and refer to them by a group name in the +- * rules. +- * Along with matching values by simple string equality, and for +- * membership in a group defined previously, rules may also contain +- * "wildcard" values - "*" - which always match. These usually appear +- * near the end. +- * +- * Grammer +- * ------- +- * (It might be helpful to look at a file like rules/evdev along with +- * this grammer. Comments, whitespace, etc. are not shown.) +- * +- * File ::= { "!" (Group | RuleSet) } +- * +- * Group ::= GroupName "=" { GroupElement } "\n" +- * GroupName ::= "$" +- * GroupElement ::= +- * +- * RuleSet ::= Mapping { Rule } +- * +- * Mapping ::= { Mlvo } "=" { Kccgst } "\n" +- * Mlvo ::= "model" | "option" | ("layout" | "variant") [ Index ] +- * Index ::= "[" 1..XKB_NUM_GROUPS "]" +- * Kccgst ::= "keycodes" | "symbols" | "types" | "compat" | "geometry" +- * +- * Rule ::= { MlvoValue } "=" { KccgstValue } "\n" +- * MlvoValue ::= "*" | GroupName | +- * KccgstValue ::= +- * +- * Notes: +- * - The order of values in a Rule must be the same as the Mapping it +- * follows. The mapping line determines the meaning of the values in +- * the rules which follow in the RuleSet. +- * - If a Rule is matched, %-expansion is performed on the KccgstValue, +- * as follows: +- * %m, %l, %v: +- * The model, layout or variant, if only one was given (e.g. +- * %l for "us,il" is invalid). +- * %l[1], %v[1]: +- * Layout or variant for the specified group Index, if more than +- * one was given (e.g. %l[1] for "us" is invalid). +- * %+m, %+l, %+v, %+l[1], %+v[1] +- * As above, but prefixed with '+'. Similarly, '|', '-', '_' may be +- * used instead of '+'. +- * %(m), %(l), %(l[1]), %(v), %(v[1]): +- * As above, but prefixed by '(' and suffixed by ')'. +- * In case the expansion is invalid, as described above, it is +- * skipped (the rest of the string is still processed); this includes +- * the prefix and suffix (that's why you shouldn't use e.g. "(%v[1])"). +- */ +- + /* Scanner / Lexer */ + + /* Values returned with some tokens, like yylval. */ +@@ -137,14 +59,6 @@ union lvalue { + struct sval string; + }; + +-/* +- * Holds the location in the file of the last processed token, +- * like yylloc. +- */ +-struct location { +- int line, column; +-}; +- + enum rules_token { + TOK_END_OF_FILE = 0, + TOK_END_OF_LINE, +@@ -156,14 +70,6 @@ enum rules_token { + TOK_ERROR + }; + +-/* C99 is stupid. Just use the 1 variant when there are no args. */ +-#define scanner_error1(scanner, loc, msg) \ +- log_warn((scanner)->ctx, "rules/%s:%d:%d: %s\n", \ +- (scanner)->file_name, (loc)->line, (loc)->column, msg) +-#define scanner_error(scanner, loc, fmt, ...) \ +- log_warn((scanner)->ctx, "rules/%s:%d:%d: " fmt "\n", \ +- (scanner)->file_name, (loc)->line, (loc)->column, __VA_ARGS__) +- + static inline bool + is_ident(char ch) + { +@@ -171,7 +77,7 @@ is_ident(char ch) + } + + static enum rules_token +-lex(struct scanner *s, union lvalue *val, struct location *loc) ++lex(struct scanner *s, union lvalue *val) + { + skip_more_whitespace_and_comments: + /* Skip spaces. */ +@@ -191,8 +97,7 @@ skip_more_whitespace_and_comments: + /* Escaped line continuation. */ + if (chr(s, '\\')) { + if (!eol(s)) { +- scanner_error1(s, loc, +- "illegal new line escape; must appear at end of line"); ++ scanner_err(s, "illegal new line escape; must appear at end of line"); + return TOK_ERROR; + } + next(s); +@@ -203,8 +108,8 @@ skip_more_whitespace_and_comments: + if (eof(s)) return TOK_END_OF_FILE; + + /* New token. */ +- loc->line = s->line; +- loc->column = s->column; ++ s->token_line = s->line; ++ s->token_column = s->column; + + /* Operators and punctuation. */ + if (chr(s, '!')) return TOK_BANG; +@@ -220,8 +125,7 @@ skip_more_whitespace_and_comments: + val->string.len++; + } + if (val->string.len == 0) { +- scanner_error1(s, loc, +- "unexpected character after \'$\'; expected name"); ++ scanner_err(s, "unexpected character after \'$\'; expected name"); + return TOK_ERROR; + } + return TOK_GROUP_NAME; +@@ -238,7 +142,7 @@ skip_more_whitespace_and_comments: + return TOK_IDENTIFIER; + } + +- scanner_error1(s, loc, "unrecognized token"); ++ scanner_err(s, "unrecognized token"); + return TOK_ERROR; + } + +@@ -330,7 +234,6 @@ struct matcher { + struct xkb_context *ctx; + /* Input.*/ + struct rule_names rmlvo; +- struct location loc; + union lvalue val; + struct scanner scanner; + darray(struct group) groups; +@@ -410,10 +313,8 @@ matcher_free(struct matcher *m) + free(m); + } + +-#define matcher_error1(matcher, msg) \ +- scanner_error1(&(matcher)->scanner, &(matcher)->loc, msg) +-#define matcher_error(matcher, fmt, ...) \ +- scanner_error(&(matcher)->scanner, &(matcher)->loc, fmt, __VA_ARGS__) ++#define matcher_err(matcher, fmt, ...) \ ++ scanner_err(&(matcher)->scanner, fmt, ## __VA_ARGS__) + + static void + matcher_group_start_new(struct matcher *m, struct sval name) +@@ -474,19 +375,15 @@ matcher_mapping_set_mlvo(struct matcher + + /* Not found. */ + if (mlvo >= _MLVO_NUM_ENTRIES) { +- matcher_error(m, +- "invalid mapping: %.*s is not a valid value here; " +- "ignoring rule set", +- ident.len, ident.start); ++ matcher_err(m, "invalid mapping: %.*s is not a valid value here; ignoring rule set", ++ ident.len, ident.start); + m->mapping.skip = true; + return; + } + +- if (m->mapping.defined_mlvo_mask & (1 << mlvo)) { +- matcher_error(m, +- "invalid mapping: %.*s appears twice on the same line; " +- "ignoring rule set", +- mlvo_sval.len, mlvo_sval.start); ++ if (m->mapping.defined_mlvo_mask & (1u << mlvo)) { ++ matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set", ++ mlvo_sval.len, mlvo_sval.start); + m->mapping.skip = true; + return; + } +@@ -497,10 +394,8 @@ matcher_mapping_set_mlvo(struct matcher + int consumed = extract_layout_index(ident.start + mlvo_sval.len, + ident.len - mlvo_sval.len, &idx); + if ((int) (ident.len - mlvo_sval.len) != consumed) { +- matcher_error(m, +- "invalid mapping:\" %.*s\" may only be followed by a valid group index; " +- "ignoring rule set", +- mlvo_sval.len, mlvo_sval.start); ++ matcher_err(m, "invalid mapping: \"%.*s\" may only be followed by a valid group index; ignoring rule set", ++ mlvo_sval.len, mlvo_sval.start); + m->mapping.skip = true; + return; + } +@@ -512,17 +407,15 @@ matcher_mapping_set_mlvo(struct matcher + m->mapping.variant_idx = idx; + } + else { +- matcher_error(m, +- "invalid mapping: \"%.*s\" cannot be followed by a group index; " +- "ignoring rule set", +- mlvo_sval.len, mlvo_sval.start); ++ matcher_err(m, "invalid mapping: \"%.*s\" cannot be followed by a group index; ignoring rule set", ++ mlvo_sval.len, mlvo_sval.start); + m->mapping.skip = true; + return; + } + } + + m->mapping.mlvo_at_pos[m->mapping.num_mlvo] = mlvo; +- m->mapping.defined_mlvo_mask |= 1 << mlvo; ++ m->mapping.defined_mlvo_mask |= 1u << mlvo; + m->mapping.num_mlvo++; + } + +@@ -541,25 +434,21 @@ matcher_mapping_set_kccgst(struct matche + + /* Not found. */ + if (kccgst >= _KCCGST_NUM_ENTRIES) { +- matcher_error(m, +- "invalid mapping: %.*s is not a valid value here; " +- "ignoring rule set", +- ident.len, ident.start); ++ matcher_err(m, "invalid mapping: %.*s is not a valid value here; ignoring rule set", ++ ident.len, ident.start); + m->mapping.skip = true; + return; + } + +- if (m->mapping.defined_kccgst_mask & (1 << kccgst)) { +- matcher_error(m, +- "invalid mapping: %.*s appears twice on the same line; " +- "ignoring rule set", +- kccgst_sval.len, kccgst_sval.start); ++ if (m->mapping.defined_kccgst_mask & (1u << kccgst)) { ++ matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set", ++ kccgst_sval.len, kccgst_sval.start); + m->mapping.skip = true; + return; + } + + m->mapping.kccgst_at_pos[m->mapping.num_kccgst] = kccgst; +- m->mapping.defined_kccgst_mask |= 1 << kccgst; ++ m->mapping.defined_kccgst_mask |= 1u << kccgst; + m->mapping.num_kccgst++; + } + +@@ -567,16 +456,12 @@ static void + matcher_mapping_verify(struct matcher *m) + { + if (m->mapping.num_mlvo == 0) { +- matcher_error1(m, +- "invalid mapping: must have at least one value on the left hand side; " +- "ignoring rule set"); ++ matcher_err(m, "invalid mapping: must have at least one value on the left hand side; ignoring rule set"); + goto skip; + } + + if (m->mapping.num_kccgst == 0) { +- matcher_error1(m, +- "invalid mapping: must have at least one value on the right hand side; " +- "ignoring rule set"); ++ matcher_err(m, "invalid mapping: must have at least one value on the right hand side; ignoring rule set"); + goto skip; + } + +@@ -585,7 +470,7 @@ matcher_mapping_verify(struct matcher *m + * See the "Notes" section in the overview above. + */ + +- if (m->mapping.defined_mlvo_mask & (1 << MLVO_LAYOUT)) { ++ if (m->mapping.defined_mlvo_mask & (1u << MLVO_LAYOUT)) { + if (m->mapping.layout_idx == XKB_LAYOUT_INVALID) { + if (darray_size(m->rmlvo.layouts) > 1) + goto skip; +@@ -597,7 +482,7 @@ matcher_mapping_verify(struct matcher *m + } + } + +- if (m->mapping.defined_mlvo_mask & (1 << MLVO_VARIANT)) { ++ if (m->mapping.defined_mlvo_mask & (1u << MLVO_VARIANT)) { + if (m->mapping.variant_idx == XKB_LAYOUT_INVALID) { + if (darray_size(m->rmlvo.variants) > 1) + goto skip; +@@ -627,9 +512,7 @@ matcher_rule_set_mlvo_common(struct matc + enum mlvo_match_type match_type) + { + if (m->rule.num_mlvo_values + 1 > m->mapping.num_mlvo) { +- matcher_error1(m, +- "invalid rule: has more values than the mapping line; " +- "ignoring rule"); ++ matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule"); + m->rule.skip = true; + return; + } +@@ -661,9 +544,7 @@ static void + matcher_rule_set_kccgst(struct matcher *m, struct sval ident) + { + if (m->rule.num_kccgst_values + 1 > m->mapping.num_kccgst) { +- matcher_error1(m, +- "invalid rule: has more values than the mapping line; " +- "ignoring rule"); ++ matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule"); + m->rule.skip = true; + return; + } +@@ -720,20 +601,10 @@ static bool + append_expanded_kccgst_value(struct matcher *m, darray_char *to, + struct sval value) + { +- const size_t original_size = darray_size(*to); + const char *s = value.start; +- +- /* +- * Appending bar to foo -> foo (not an error if this happens) +- * Appending +bar to foo -> foo+bar +- * Appending bar to +foo -> bar+foo +- * Appending +bar to +foo -> +foo+bar +- */ +- if (!darray_empty(*to) && s[0] != '+' && s[0] != '|') { +- if (darray_item(*to, 0) == '+' || darray_item(*to, 0) == '|') +- darray_prepend_items_nullterminate(*to, value.start, value.len); +- return true; +- } ++ darray_char expanded = darray_new(); ++ char ch; ++ bool expanded_plus, to_plus; + + /* + * Some ugly hand-lexing here, but going through the scanner is more +@@ -743,12 +614,12 @@ append_expanded_kccgst_value(struct matc + enum rules_mlvo mlv; + xkb_layout_index_t idx; + char pfx, sfx; +- struct sval expanded; ++ struct sval expanded_value; + + /* Check if that's a start of an expansion. */ + if (s[i] != '%') { + /* Just a normal character. */ +- darray_append_items_nullterminate(*to, &s[i++], 1); ++ darray_appends_nullterminate(expanded, &s[i++], 1); + continue; + } + if (++i >= value.len) goto error; +@@ -777,9 +648,7 @@ append_expanded_kccgst_value(struct matc + int consumed; + + if (mlv != MLVO_LAYOUT && mlv != MLVO_VARIANT) { +- matcher_error1(m, +- "invalid index in %%-expansion; " +- "may only index layout or variant"); ++ matcher_err(m, "invalid index in %%-expansion; may only index layout or variant"); + goto error; + } + +@@ -795,46 +664,65 @@ append_expanded_kccgst_value(struct matc + } + + /* Get the expanded value. */ +- expanded.len = 0; ++ expanded_value.len = 0; + + if (mlv == MLVO_LAYOUT) { + if (idx != XKB_LAYOUT_INVALID && + idx < darray_size(m->rmlvo.layouts) && + darray_size(m->rmlvo.layouts) > 1) +- expanded = darray_item(m->rmlvo.layouts, idx); ++ expanded_value = darray_item(m->rmlvo.layouts, idx); + else if (idx == XKB_LAYOUT_INVALID && + darray_size(m->rmlvo.layouts) == 1) +- expanded = darray_item(m->rmlvo.layouts, 0); ++ expanded_value = darray_item(m->rmlvo.layouts, 0); + } + else if (mlv == MLVO_VARIANT) { + if (idx != XKB_LAYOUT_INVALID && + idx < darray_size(m->rmlvo.variants) && + darray_size(m->rmlvo.variants) > 1) +- expanded = darray_item(m->rmlvo.variants, idx); ++ expanded_value = darray_item(m->rmlvo.variants, idx); + else if (idx == XKB_LAYOUT_INVALID && + darray_size(m->rmlvo.variants) == 1) +- expanded = darray_item(m->rmlvo.variants, 0); ++ expanded_value = darray_item(m->rmlvo.variants, 0); + } + else if (mlv == MLVO_MODEL) { +- expanded = m->rmlvo.model; ++ expanded_value = m->rmlvo.model; + } + + /* If we didn't get one, skip silently. */ +- if (expanded.len <= 0) ++ if (expanded_value.len <= 0) + continue; + + if (pfx != 0) +- darray_append_items_nullterminate(*to, &pfx, 1); +- darray_append_items_nullterminate(*to, expanded.start, expanded.len); ++ darray_appends_nullterminate(expanded, &pfx, 1); ++ darray_appends_nullterminate(expanded, ++ expanded_value.start, expanded_value.len); + if (sfx != 0) +- darray_append_items_nullterminate(*to, &sfx, 1); ++ darray_appends_nullterminate(expanded, &sfx, 1); + } + ++ /* ++ * Appending bar to foo -> foo (not an error if this happens) ++ * Appending +bar to foo -> foo+bar ++ * Appending bar to +foo -> bar+foo ++ * Appending +bar to +foo -> +foo+bar ++ */ ++ ++ ch = (darray_empty(expanded) ? '\0' : darray_item(expanded, 0)); ++ expanded_plus = (ch == '+' || ch == '|'); ++ ch = (darray_empty(*to) ? '\0' : darray_item(*to, 0)); ++ to_plus = (ch == '+' || ch == '|'); ++ ++ if (expanded_plus || darray_empty(*to)) ++ darray_appends_nullterminate(*to, expanded.item, expanded.size); ++ else if (to_plus) ++ darray_prepends_nullterminate(*to, expanded.item, expanded.size); ++ ++ darray_free(expanded); + return true; + + error: +- matcher_error1(m, "invalid %%-expansion in value; not used"); +- darray_resize(*to, original_size); ++ darray_free(expanded); ++ matcher_err(m, "invalid %%-expansion in value; not used"); + return false; + } + +@@ -843,9 +731,7 @@ matcher_rule_verify(struct matcher *m) + { + if (m->rule.num_mlvo_values != m->mapping.num_mlvo || + m->rule.num_kccgst_values != m->mapping.num_kccgst) { +- matcher_error1(m, +- "invalid rule: must have same number of values as mapping line;" +- "ignoring rule"); ++ matcher_err(m, "invalid rule: must have same number of values as mapping line; ignoring rule"); + m->rule.skip = true; + } + } +@@ -907,7 +793,7 @@ matcher_rule_apply_if_matches(struct mat + static enum rules_token + gettok(struct matcher *m) + { +- return lex(&m->scanner, &m->val, &m->loc); ++ return lex(&m->scanner, &m->val); + } + + static bool +@@ -1068,7 +954,7 @@ finish: + return true; + + state_error: +- matcher_error1(m, "unexpected token"); ++ matcher_err(m, "unexpected token"); + error: + return false; + } +@@ -1091,12 +977,13 @@ xkb_components_from_rules(struct xkb_con + + ret = map_file(file, &string, &size); + if (!ret) { +- log_err(ctx, "Couldn't read rules file: %s\n", strerror(errno)); ++ log_err(ctx, "Couldn't read rules file \"%s\": %s\n", ++ path, strerror(errno)); + goto err_file; + } + + matcher = matcher_new(ctx, rmlvo); +- ret = matcher_match(matcher, string, size, rmlvo->rules, out); ++ ret = matcher_match(matcher, string, size, path, out); + if (!ret) + log_err(ctx, "No components returned from XKB rules \"%s\"\n", path); + matcher_free(matcher); +--- a/src/3rdparty/xkbcommon/src/xkbcomp/scanner-utils.h ++++ /dev/null +@@ -1,145 +0,0 @@ +-/* +- * Copyright © 2012 Ran Benita +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice (including the next +- * paragraph) shall be included in all copies or substantial portions of the +- * Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +- * DEALINGS IN THE SOFTWARE. +- */ +- +-#ifndef XKBCOMP_SCANNER_UTILS_H +-#define XKBCOMP_SCANNER_UTILS_H +- +-/* Point to some substring in the file; used to avoid copying. */ +-struct sval { +- const char *start; +- unsigned int len; +-}; +-typedef darray(struct sval) darray_sval; +- +-static inline bool +-svaleq(struct sval s1, struct sval s2) +-{ +- return s1.len == s2.len && strncmp(s1.start, s2.start, s1.len) == 0; +-} +- +-static inline bool +-svaleq_prefix(struct sval s1, struct sval s2) +-{ +- return s1.len <= s2.len && strncmp(s1.start, s2.start, s1.len) == 0; +-} +- +-struct scanner { +- const char *s; +- size_t pos; +- size_t len; +- char buf[1024]; +- size_t buf_pos; +- int line, column; +- /* The line/column of the start of the current token. */ +- int token_line, token_column; +- const char *file_name; +- struct xkb_context *ctx; +-}; +- +-static inline void +-scanner_init(struct scanner *s, struct xkb_context *ctx, +- const char *string, size_t len, const char *file_name) +-{ +- s->s = string; +- s->len = len; +- s->pos = 0; +- s->line = s->column = 1; +- s->token_line = s->token_column = 1; +- s->file_name = file_name; +- s->ctx = ctx; +-} +- +-static inline char +-peek(struct scanner *s) +-{ +- return s->pos < s->len ? s->s[s->pos] : '\0'; +-} +- +-static inline bool +-eof(struct scanner *s) +-{ +- return s->pos >= s->len; +-} +- +-static inline bool +-eol(struct scanner *s) +-{ +- return peek(s) == '\n'; +-} +- +-static inline char +-next(struct scanner *s) +-{ +- if (eof(s)) +- return '\0'; +- if (eol(s)) { +- s->line++; +- s->column = 1; +- } +- else { +- s->column++; +- } +- return s->s[s->pos++]; +-} +- +-static inline bool +-chr(struct scanner *s, char ch) +-{ +- if (peek(s) != ch) +- return false; +- s->pos++; s->column++; +- return true; +-} +- +-static inline bool +-str(struct scanner *s, const char *string, size_t len) +-{ +- if (s->len - s->pos < len) +- return false; +- if (strncasecmp(s->s + s->pos, string, len) != 0) +- return false; +- s->pos += len; s->column += len; +- return true; +-} +- +-#define lit(s, literal) str(s, literal, sizeof(literal) - 1) +- +-static inline bool +-buf_append(struct scanner *s, char ch) +-{ +- if (s->buf_pos + 1 >= sizeof(s->buf)) +- return false; +- s->buf[s->buf_pos++] = ch; +- return true; +-} +- +-static inline bool +-oct(struct scanner *s, uint8_t *out) +-{ +- int i; +- for (i = 0, *out = 0; peek(s) >= '0' && peek(s) <= '7' && i < 3; i++) +- *out = *out * 8 + next(s) - '0'; +- return i > 0; +-} +- +-#endif +--- a/src/3rdparty/xkbcommon/src/xkbcomp/scanner.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/scanner.c +@@ -23,27 +23,6 @@ + + #include "xkbcomp-priv.h" + #include "parser-priv.h" +-#include "scanner-utils.h" +- +-static void +-scanner_log(enum xkb_log_level level, struct scanner *s, const char *msg) +-{ +- xkb_log(s->ctx, level, 0, "%s:%d:%d: %s\n", s->file_name, +- s->token_line, s->token_column, msg); +-} +- +-int +-scanner_error(struct scanner *s, const char *msg) +-{ +- scanner_log(XKB_LOG_LEVEL_ERROR, s, msg); +- return ERROR_TOK; +-} +- +-void +-scanner_warn(struct scanner *s, const char *msg) +-{ +- scanner_log(XKB_LOG_LEVEL_WARNING, s, msg); +-} + + static bool + number(struct scanner *s, int64_t *out, int *out_tok) +@@ -123,11 +102,13 @@ skip_more_whitespace_and_comments: + buf_append(s, next(s)); + } + } +- if (!buf_append(s, '\0') || !chr(s, '\"')) +- return scanner_error(s, "unterminated string literal"); ++ if (!buf_append(s, '\0') || !chr(s, '\"')) { ++ scanner_err(s, "unterminated string literal"); ++ return ERROR_TOK; ++ } + yylval->str = strdup(s->buf); + if (!yylval->str) +- return scanner_error(s, "scanner out of memory"); ++ return ERROR_TOK; + return STRING; + } + +@@ -135,8 +116,10 @@ skip_more_whitespace_and_comments: + if (chr(s, '<')) { + while (is_graph(peek(s)) && peek(s) != '>') + buf_append(s, next(s)); +- if (!buf_append(s, '\0') || !chr(s, '>')) +- return scanner_error(s, "unterminated key name literal"); ++ if (!buf_append(s, '\0') || !chr(s, '>')) { ++ scanner_err(s, "unterminated key name literal"); ++ return ERROR_TOK; ++ } + /* Empty key name literals are allowed. */ + yylval->sval = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1); + return KEYNAME; +@@ -165,27 +148,32 @@ skip_more_whitespace_and_comments: + s->buf_pos = 0; + while (is_alnum(peek(s)) || peek(s) == '_') + buf_append(s, next(s)); +- if (!buf_append(s, '\0')) +- return scanner_error(s, "identifier too long"); ++ if (!buf_append(s, '\0')) { ++ scanner_err(s, "identifier too long"); ++ return ERROR_TOK; ++ } + + /* Keyword. */ +- tok = keyword_to_token(s->buf); ++ tok = keyword_to_token(s->buf, s->buf_pos - 1); + if (tok != -1) return tok; + + yylval->str = strdup(s->buf); + if (!yylval->str) +- return scanner_error(s, "scanner out of memory"); ++ return ERROR_TOK; + return IDENT; + } + + /* Number literal (hexadecimal / decimal / float). */ + if (number(s, &yylval->num, &tok)) { +- if (tok == ERROR_TOK) +- return scanner_error(s, "malformed number literal"); ++ if (tok == ERROR_TOK) { ++ scanner_err(s, "malformed number literal"); ++ return ERROR_TOK; ++ } + return tok; + } + +- return scanner_error(s, "unrecognized token"); ++ scanner_err(s, "unrecognized token"); ++ return ERROR_TOK; + } + + XkbFile * +--- a/src/3rdparty/xkbcommon/src/xkbcomp/symbols.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/symbols.c +@@ -125,12 +125,11 @@ ClearGroupInfo(GroupInfo *groupi) + static void + CopyGroupInfo(GroupInfo *to, const GroupInfo *from) + { +- xkb_level_index_t j; + to->defined = from->defined; + to->type = from->type; + darray_init(to->levels); + darray_copy(to->levels, from->levels); +- for (j = 0; j < darray_size(to->levels); j++) ++ for (xkb_level_index_t j = 0; j < darray_size(to->levels); j++) + if (darray_item(from->levels, j).num_syms > 1) + darray_item(to->levels, j).u.syms = + memdup(darray_item(from->levels, j).u.syms, +@@ -480,7 +479,6 @@ static void + MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from, + enum merge_mode merge) + { +- unsigned int i; + KeyInfo *keyi; + ModMapEntry *mm; + xkb_atom_t *group_name; +@@ -498,7 +496,7 @@ MergeIncludedSymbols(SymbolsInfo *into, + + group_names_in_both = MIN(darray_size(into->group_names), + darray_size(from->group_names)); +- for (i = 0; i < group_names_in_both; i++) { ++ for (xkb_layout_index_t i = 0; i < group_names_in_both; i++) { + if (!darray_item(from->group_names, i)) + continue; + +@@ -511,16 +509,28 @@ MergeIncludedSymbols(SymbolsInfo *into, + darray_foreach_from(group_name, from->group_names, group_names_in_both) + darray_append(into->group_names, *group_name); + +- darray_foreach(keyi, from->keys) { +- keyi->merge = (merge == MERGE_DEFAULT ? keyi->merge : merge); +- if (!AddKeySymbols(into, keyi, false)) +- into->errorCount++; ++ if (darray_empty(into->keys)) { ++ into->keys = from->keys; ++ darray_init(from->keys); ++ } ++ else { ++ darray_foreach(keyi, from->keys) { ++ keyi->merge = (merge == MERGE_DEFAULT ? keyi->merge : merge); ++ if (!AddKeySymbols(into, keyi, false)) ++ into->errorCount++; ++ } + } + +- darray_foreach(mm, from->modmaps) { +- mm->merge = (merge == MERGE_DEFAULT ? mm->merge : merge); +- if (!AddModMapEntry(into, mm)) +- into->errorCount++; ++ if (darray_empty(into->modmaps)) { ++ into->modmaps = from->modmaps; ++ darray_init(from->modmaps); ++ } ++ else { ++ darray_foreach(mm, from->modmaps) { ++ mm->merge = (merge == MERGE_DEFAULT ? mm->merge : merge); ++ if (!AddModMapEntry(into, mm)) ++ into->errorCount++; ++ } + } + } + +@@ -633,8 +643,6 @@ AddSymbolsToKey(SymbolsInfo *info, KeyIn + xkb_layout_index_t ndx; + GroupInfo *groupi; + xkb_level_index_t nLevels; +- xkb_level_index_t i; +- int j; + + if (!GetGroupIndex(info, keyi, arrayNdx, SYMBOLS, &ndx)) + return false; +@@ -669,7 +677,7 @@ AddSymbolsToKey(SymbolsInfo *info, KeyIn + + groupi->defined |= GROUP_FIELD_SYMS; + +- for (i = 0; i < nLevels; i++) { ++ for (xkb_level_index_t i = 0; i < nLevels; i++) { + unsigned int sym_index; + struct xkb_level *leveli = &darray_item(groupi->levels, i); + +@@ -678,7 +686,7 @@ AddSymbolsToKey(SymbolsInfo *info, KeyIn + if (leveli->num_syms > 1) + leveli->u.syms = calloc(leveli->num_syms, sizeof(*leveli->u.syms)); + +- for (j = 0; j < leveli->num_syms; j++) { ++ for (unsigned j = 0; j < leveli->num_syms; j++) { + xkb_keysym_t keysym = darray_item(value->keysym_list.syms, + sym_index + j); + +@@ -701,7 +709,6 @@ static bool + AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx, + ExprDef *value) + { +- unsigned int i; + xkb_layout_index_t ndx; + GroupInfo *groupi; + unsigned int nActs; +@@ -742,7 +749,7 @@ AddActionsToKey(SymbolsInfo *info, KeyIn + groupi->defined |= GROUP_FIELD_ACTS; + + act = value->unary.child; +- for (i = 0; i < nActs; i++) { ++ for (unsigned i = 0; i < nActs; i++) { + union xkb_action *toAct = &darray_item(groupi->levels, i).action; + + if (!HandleActionDef(act, info->keymap, toAct, info->actions)) +@@ -772,19 +779,20 @@ static bool + SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field, + ExprDef *arrayNdx, ExprDef *value) + { +- bool ok = true; + struct xkb_context *ctx = info->keymap->ctx; + + if (istreq(field, "type")) { + xkb_layout_index_t ndx; + xkb_atom_t val; + +- if (!ExprResolveString(ctx, value, &val)) +- log_vrb(ctx, 1, ++ if (!ExprResolveString(ctx, value, &val)) { ++ log_err(ctx, + "The type field of a key symbol map must be a string; " + "Ignoring illegal type definition\n"); ++ return false; ++ } + +- if (arrayNdx == NULL) { ++ if (!arrayNdx) { + keyi->default_type = val; + keyi->defined |= KEY_FIELD_DEFAULT_TYPE; + } +@@ -803,32 +811,33 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + darray_item(keyi->groups, ndx).defined |= GROUP_FIELD_TYPE; + } + } +- else if (istreq(field, "symbols")) ++ else if (istreq(field, "symbols")) { + return AddSymbolsToKey(info, keyi, arrayNdx, value); +- else if (istreq(field, "actions")) ++ } ++ else if (istreq(field, "actions")) { + return AddActionsToKey(info, keyi, arrayNdx, value); ++ } + else if (istreq(field, "vmods") || + istreq(field, "virtualmods") || + istreq(field, "virtualmodifiers")) { + xkb_mod_mask_t mask; + +- ok = ExprResolveModMask(info->keymap, value, MOD_VIRT, &mask); +- if (ok) { +- keyi->vmodmap = mask; +- keyi->defined |= KEY_FIELD_VMODMAP; +- } +- else { +- log_err(info->keymap->ctx, ++ if (!ExprResolveModMask(info->keymap, value, MOD_VIRT, &mask)) { ++ log_err(ctx, + "Expected a virtual modifier mask, found %s; " + "Ignoring virtual modifiers definition for key %s\n", + expr_op_type_to_string(value->expr.op), + KeyInfoText(info, keyi)); ++ return false; + } ++ ++ keyi->vmodmap = mask; ++ keyi->defined |= KEY_FIELD_VMODMAP; + } + else if (istreq(field, "locking") || + istreq(field, "lock") || + istreq(field, "locks")) { +- log_err(info->keymap->ctx, ++ log_vrb(ctx, 1, + "Key behaviors not supported; " + "Ignoring locking specification for key %s\n", + KeyInfoText(info, keyi)); +@@ -836,14 +845,14 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + else if (istreq(field, "radiogroup") || + istreq(field, "permanentradiogroup") || + istreq(field, "allownone")) { +- log_err(info->keymap->ctx, ++ log_vrb(ctx, 1, + "Radio groups not supported; " + "Ignoring radio group specification for key %s\n", + KeyInfoText(info, keyi)); + } + else if (istreq_prefix("overlay", field) || + istreq_prefix("permanentoverlay", field)) { +- log_err(info->keymap->ctx, ++ log_vrb(ctx, 1, + "Overlays not supported; " + "Ignoring overlay specification for key %s\n", + KeyInfoText(info, keyi)); +@@ -853,14 +862,14 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + istreq(field, "repeat")) { + unsigned int val; + +- ok = ExprResolveEnum(ctx, value, &val, repeatEntries); +- if (!ok) { +- log_err(info->keymap->ctx, ++ if (!ExprResolveEnum(ctx, value, &val, repeatEntries)) { ++ log_err(ctx, + "Illegal repeat setting for %s; " + "Non-boolean repeat setting ignored\n", + KeyInfoText(info, keyi)); + return false; + } ++ + keyi->repeat = val; + keyi->defined |= KEY_FIELD_REPEAT; + } +@@ -869,18 +878,14 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + bool set; + + if (!ExprResolveBoolean(ctx, value, &set)) { +- log_err(info->keymap->ctx, ++ log_err(ctx, + "Illegal groupsWrap setting for %s; " + "Non-boolean value ignored\n", + KeyInfoText(info, keyi)); + return false; + } + +- if (set) +- keyi->out_of_range_group_action = RANGE_WRAP; +- else +- keyi->out_of_range_group_action = RANGE_SATURATE; +- ++ keyi->out_of_range_group_action = (set ? RANGE_WRAP : RANGE_SATURATE); + keyi->defined |= KEY_FIELD_GROUPINFO; + } + else if (istreq(field, "groupsclamp") || +@@ -888,18 +893,14 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + bool set; + + if (!ExprResolveBoolean(ctx, value, &set)) { +- log_err(info->keymap->ctx, ++ log_err(ctx, + "Illegal groupsClamp setting for %s; " + "Non-boolean value ignored\n", + KeyInfoText(info, keyi)); + return false; + } + +- if (set) +- keyi->out_of_range_group_action = RANGE_SATURATE; +- else +- keyi->out_of_range_group_action = RANGE_WRAP; +- ++ keyi->out_of_range_group_action = (set ? RANGE_SATURATE : RANGE_WRAP); + keyi->defined |= KEY_FIELD_GROUPINFO; + } + else if (istreq(field, "groupsredirect") || +@@ -907,7 +908,7 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + xkb_layout_index_t grp; + + if (!ExprResolveGroup(ctx, value, &grp)) { +- log_err(info->keymap->ctx, ++ log_err(ctx, + "Illegal group index for redirect of key %s; " + "Definition with non-integer group ignored\n", + KeyInfoText(info, keyi)); +@@ -919,17 +920,17 @@ SetSymbolsField(SymbolsInfo *info, KeyIn + keyi->defined |= KEY_FIELD_GROUPINFO; + } + else { +- log_err(info->keymap->ctx, ++ log_err(ctx, + "Unknown field %s in a symbol interpretation; " + "Definition ignored\n", + field); +- ok = false; ++ return false; + } + +- return ok; ++ return true; + } + +-static int ++static bool + SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value) + { + xkb_layout_index_t group, group_to_use; +@@ -979,16 +980,16 @@ SetGroupName(SymbolsInfo *info, ExprDef + return true; + } + +-static int ++static bool + HandleGlobalVar(SymbolsInfo *info, VarDef *stmt) + { + const char *elem, *field; + ExprDef *arrayNdx; + bool ret; + +- if (ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, +- &arrayNdx) == 0) +- return 0; /* internal error, already reported */ ++ if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &arrayNdx)) ++ return false; ++ + if (elem && istreq(elem, "key")) { + ret = SetSymbolsField(info, &info->default_key, field, arrayNdx, + stmt->value); +@@ -1098,16 +1099,15 @@ SetExplicitGroup(SymbolsInfo *info, KeyI + return true; + } + +-static int ++static bool + HandleSymbolsDef(SymbolsInfo *info, SymbolsDef *stmt) + { + KeyInfo keyi; +- xkb_layout_index_t i; + + keyi = info->default_key; + darray_init(keyi.groups); + darray_copy(keyi.groups, info->default_key.groups); +- for (i = 0; i < darray_size(keyi.groups); i++) ++ for (xkb_layout_index_t i = 0; i < darray_size(keyi.groups); i++) + CopyGroupInfo(&darray_item(keyi.groups, i), + &darray_item(info->default_key.groups, i)); + keyi.merge = stmt->merge; +@@ -1134,7 +1134,6 @@ HandleSymbolsDef(SymbolsInfo *info, Symb + static bool + HandleModMapDef(SymbolsInfo *info, ModMapDef *def) + { +- ExprDef *key; + ModMapEntry tmp; + xkb_mod_index_t ndx; + bool ok; +@@ -1153,7 +1152,7 @@ HandleModMapDef(SymbolsInfo *info, ModMa + tmp.modifier = ndx; + tmp.merge = def->merge; + +- for (key = def->keys; key != NULL; key = (ExprDef *) key->common.next) { ++ for (ExprDef *key = def->keys; key; key = (ExprDef *) key->common.next) { + xkb_keysym_t sym; + + if (key->expr.op == EXPR_VALUE && +@@ -1198,7 +1197,7 @@ HandleSymbolsFile(SymbolsInfo *info, Xkb + ok = HandleGlobalVar(info, (VarDef *) stmt); + break; + case STMT_VMOD: +- ok = HandleVModDef(info->keymap, (VModDef *) stmt); ++ ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge); + break; + case STMT_MODMAP: + ok = HandleModMapDef(info, (ModMapDef *) stmt); +@@ -1518,7 +1517,7 @@ CopyModMapDef(SymbolsInfo *info, ModMapE + } + } + +- key->modmap |= (1 << entry->modifier); ++ key->modmap |= (1u << entry->modifier); + return true; + } + +--- a/src/3rdparty/xkbcommon/src/xkbcomp/types.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/types.c +@@ -30,111 +30,6 @@ + #include "expr.h" + #include "include.h" + +-/* +- * The xkb_types section +- * ===================== +- * This section is the second to be processesed, after xkb_keycodes. +- * However, it is completely independent and could have been the first +- * to be processed (it does not refer to specific keys as specified in +- * the xkb_keycodes section). +- * +- * This section defines key types, which, given a key and a keyboard +- * state (i.e. modifier state and group), determine the shift level to +- * be used in translating the key to keysyms. These types are assigned +- * to each group in each key, in the xkb_symbols section. +- * +- * Key types are called this way because, in a way, they really describe +- * the "type" of the key (or more correctly, a specific group of the +- * key). For example, an ordinary keymap will provide a type called +- * "KEYPAD", which consists of two levels, with the second level being +- * chosen according to the state of the Num Lock (or Shift) modifiers. +- * Another example is a type called "ONE_LEVEL", which is usually +- * assigned to keys such as Escape; these have just one level and are +- * not affected by the modifier state. Yet more common examples are +- * "TWO_LEVEL" (with Shift choosing the second level), "ALPHABETIC" +- * (where Caps Lock may also choose the second level), etc. +- * +- * Type definitions +- * ---------------- +- * Statements of the form: +- * type "FOUR_LEVEL" { ... } +- * +- * The above would create a new type named "FOUR_LEVEL". +- * The body of the definition may include statements of the following +- * forms: +- * +- * - level_name statements (mandatory for each level in the type): +- * level_name[Level1] = "Base"; +- * +- * Gives each level in this type a descriptive name. It isn't used +- * for any thing. +- * Note: A level may be specified as Level[1-8] or just a number (can +- * be more than 8). +- * +- * - modifiers statement (mandatory, should be specified only once): +- * modifiers = Shift+Lock+LevelThree; +- * +- * A mask of real and virtual modifiers. These are the only modifiers +- * being considered when matching the modifier state against the type. +- * The other modifiers, whether active or not, are masked out in the +- * calculation. +- * +- * - map entry statements (should have at least as many mappings as there +- * are levels in the type): +- * map[Shift+LevelThree] = Level4; +- * +- * If the active modifiers, masked with the type's modifiers (as stated +- * above), match (i.e. equal) the modifiers inside the map[] statement, +- * then the level in the right hand side is chosen. For example, in the +- * above, if in the current keyboard state the Shift and LevelThree +- * modifiers are active, while the Lock modifier is not, then the +- * keysym(s) in the 4th level of the group will be returned to the +- * user. +- * +- * - preserve statements: +- * map[Shift+Lock+LevelThree] = Level5; +- * preserve[Shift+Lock+LevelThree] = Lock; +- * +- * When a map entry matches the active modifiers and the level it +- * specified is chosen, then these modifiers are said to be "consumed"; +- * for example, in a simple US keymap where the "g" key is assigned an +- * ordinary ALPHABETIC key type, if the Lock (Caps Lock) modifier is +- * active and the key is pressed, then a "G" keysym is produced (as +- * opposed to lower-case "g"). This is because the type definition has +- * a map entry like the following: +- * map[Lock] = Level2; +- * And as such the Lock modifier is consumed. This information is +- * relevant for applications which further process the modifiers, +- * since by then the consumed modifiers have already "done their part" +- * and should be masked out. +- * +- * However, sometimes even if a modifier is actually used to choose +- * the shift level (as Lock above), it should *not* be reported as +- * consumed, for various reasons. In this case, a preserve[] statement +- * can be used to augment the map entry. The modifiers inside the square +- * brackets should match one of the map[] statements in the type. The +- * right hand side should consists of modifiers from the left hand +- * side; these modifiers are then "preserved" and not reported as +- * consumed. +- * +- * Virtual modifier statements +- * --------------------------- +- * Statements of the form: +- * virtual_modifiers LControl; +- * +- * Can appear in the xkb_types, xkb_compat, xkb_symbols sections. +- * TODO +- * +- * Effect on keymap +- * ---------------- +- * After all of the xkb_types sections have been compiled, the following +- * members of struct xkb_keymap are finalized: +- * struct xkb_key_type *types; +- * unsigned int num_types; +- * char *types_section_name; +- * TODO: virtual modifiers. +- */ +- + enum type_field { + TYPE_FIELD_MASK = (1 << 0), + TYPE_FIELD_MAP = (1 << 1), +@@ -287,10 +182,16 @@ MergeIncludedKeyTypes(KeyTypesInfo *into + from->name = NULL; + } + +- darray_foreach(type, from->types) { +- type->merge = (merge == MERGE_DEFAULT ? type->merge : merge); +- if (!AddKeyType(into, type, false)) +- into->errorCount++; ++ if (darray_empty(into->types)) { ++ into->types = from->types; ++ darray_init(from->types); ++ } ++ else { ++ darray_foreach(type, from->types) { ++ type->merge = (merge == MERGE_DEFAULT ? type->merge : merge); ++ if (!AddKeyType(into, type, false)) ++ into->errorCount++; ++ } + } + } + +@@ -738,7 +639,7 @@ HandleKeyTypesFile(KeyTypesInfo *info, X + ok = true; + break; + case STMT_VMOD: +- ok = HandleVModDef(info->keymap, (VModDef *) stmt); ++ ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge); + break; + default: + log_err(info->keymap->ctx, +--- a/src/3rdparty/xkbcommon/src/xkbcomp/vmod.c ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/vmod.c +@@ -30,27 +30,64 @@ + #include "vmod.h" + + bool +-HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt) ++HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt, ++ enum merge_mode merge) + { + xkb_mod_index_t i; +- const struct xkb_mod *mod; ++ struct xkb_mod *mod; ++ xkb_mod_mask_t mapping; + struct xkb_mod new; + +- if (stmt->value) +- log_err(keymap->ctx, +- "Support for setting a value in a virtual_modifiers statement has been removed; " +- "Value ignored\n"); ++ merge = (merge == MERGE_DEFAULT ? stmt->merge : merge); ++ ++ if (stmt->value) { ++ /* ++ * This is a statement such as 'virtualModifiers NumLock = Mod1'; ++ * it sets the vmod-to-real-mod[s] mapping directly instead of going ++ * through modifier_map or some such. ++ */ ++ if (!ExprResolveModMask(keymap, stmt->value, MOD_REAL, &mapping)) { ++ log_err(keymap->ctx, ++ "Declaration of %s ignored\n", ++ xkb_atom_text(keymap->ctx, stmt->name)); ++ return false; ++ } ++ } ++ else { ++ mapping = 0; ++ } + + darray_enumerate(i, mod, keymap->mods) { + if (mod->name == stmt->name) { +- if (mod->type == MOD_VIRT) ++ if (mod->type != MOD_VIRT) { ++ log_err(keymap->ctx, ++ "Can't add a virtual modifier named \"%s\"; " ++ "there is already a non-virtual modifier with this name! Ignored\n", ++ xkb_atom_text(keymap->ctx, mod->name)); ++ return false; ++ } ++ ++ if (mod->mapping == mapping) + return true; + +- log_err(keymap->ctx, +- "Can't add a virtual modifier named \"%s\"; " +- "there is already a non-virtual modifier with this name! Ignored\n", +- xkb_atom_text(keymap->ctx, mod->name)); +- return false; ++ if (mod->mapping != 0) { ++ xkb_mod_mask_t use, ignore; ++ ++ use = (merge == MERGE_OVERRIDE ? mapping : mod->mapping); ++ ignore = (merge == MERGE_OVERRIDE ? mod->mapping : mapping); ++ ++ log_warn(keymap->ctx, ++ "Virtual modifier %s defined multiple times; " ++ "Using %s, ignoring %s\n", ++ xkb_atom_text(keymap->ctx, stmt->name), ++ ModMaskText(keymap, use), ++ ModMaskText(keymap, ignore)); ++ ++ mapping = use; ++ } ++ ++ mod->mapping = mapping; ++ return true; + } + } + +@@ -62,7 +99,7 @@ HandleVModDef(struct xkb_keymap *keymap, + } + + new.name = stmt->name; +- new.mapping = 0; ++ new.mapping = mapping; + new.type = MOD_VIRT; + darray_append(keymap->mods, new); + return true; +--- a/src/3rdparty/xkbcommon/src/xkbcomp/vmod.h ++++ b/src/3rdparty/xkbcommon/src/xkbcomp/vmod.h +@@ -28,6 +28,7 @@ + #define XKBCOMP_VMOD_H + + bool +-HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt); ++HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt, ++ enum merge_mode merge); + + #endif +--- a/src/3rdparty/xkbcommon/xkbcommon/xkbcommon-compat.h ++++ b/src/3rdparty/xkbcommon/xkbcommon/xkbcommon-compat.h +@@ -91,4 +91,8 @@ + + #define xkb_state_get_map(state) xkb_state_get_keymap(state) + ++/* Not needed anymore, since there's NO_FLAGS. */ ++#define XKB_MAP_COMPILE_PLACEHOLDER XKB_KEYMAP_COMPILE_NO_FLAGS ++#define XKB_MAP_COMPILE_NO_FLAGS XKB_KEYMAP_COMPILE_NO_FLAGS ++ + #endif +--- a/src/3rdparty/xkbcommon/xkbcommon/xkbcommon-x11.h ++++ b/src/3rdparty/xkbcommon/xkbcommon/xkbcommon-x11.h +@@ -27,6 +27,10 @@ + #include + #include + ++#ifdef __cplusplus ++extern "C" { ++#endif ++ + /** + * @file + * libxkbcommon-x11 API - Additional X11 support for xkbcommon. +@@ -163,4 +167,8 @@ xkb_x11_state_new_from_device(struct xkb + + /** @} */ + ++#ifdef __cplusplus ++} /* extern "C" */ + #endif ++ ++#endif /* _XKBCOMMON_X11_H */ +--- a/src/3rdparty/xkbcommon/xkbcommon/xkbcommon.h ++++ b/src/3rdparty/xkbcommon/xkbcommon/xkbcommon.h +@@ -305,26 +305,60 @@ typedef uint32_t xkb_led_mask_t; + /** + * Names to compile a keymap with, also known as RMLVO. + * +- * These names together are the primary identifier for a keymap. +- * If any of the members is NULL or an empty string (""), a default value is +- * used. It is recommended to use the system default by passing NULL for +- * unspecified values, instead of providing your own defaults. ++ * The names are the common configuration values by which a user picks ++ * a keymap. ++ * ++ * If the entire struct is NULL, then each field is taken to be NULL. ++ * You should prefer passing NULL instead of choosing your own defaults. + */ + struct xkb_rule_names { +- /** The rules file to use. The rules file describes how to interpret +- * the values of the model, layout, variant and options fields. */ ++ /** ++ * The rules file to use. The rules file describes how to interpret ++ * the values of the model, layout, variant and options fields. ++ * ++ * If NULL or the empty string "", a default value is used. ++ * If the XKB_DEFAULT_RULES environment variable is set, it is used ++ * as the default. Otherwise the system default is used. ++ */ + const char *rules; +- /** The keyboard model by which to interpret keycodes and LEDs. */ ++ /** ++ * The keyboard model by which to interpret keycodes and LEDs. ++ * ++ * If NULL or the empty string "", a default value is used. ++ * If the XKB_DEFAULT_MODEL environment variable is set, it is used ++ * as the default. Otherwise the system default is used. ++ */ + const char *model; +- /** A comma separated list of layouts (languages) to include in the +- * keymap. */ ++ /** ++ * A comma separated list of layouts (languages) to include in the ++ * keymap. ++ * ++ * If NULL or the empty string "", a default value is used. ++ * If the XKB_DEFAULT_LAYOUT environment variable is set, it is used ++ * as the default. Otherwise the system default is used. ++ */ + const char *layout; +- /** A comma separated list of variants, one per layout, which may +- * modify or augment the respective layout in various ways. */ ++ /** ++ * A comma separated list of variants, one per layout, which may ++ * modify or augment the respective layout in various ways. ++ * ++ * If NULL or the empty string "", and a default value is also used ++ * for the layout, a default value is used. Otherwise no variant is ++ * used. ++ * If the XKB_DEFAULT_VARIANT environment variable is set, it is used ++ * as the default. Otherwise the system default is used. ++ */ + const char *variant; +- /** A comma separated list of options, through which the user specifies +- * non-layout related preferences, like which key combinations are used +- * for switching layouts, or which key is the Compose key. */ ++ /** ++ * A comma separated list of options, through which the user specifies ++ * non-layout related preferences, like which key combinations are used ++ * for switching layouts, or which key is the Compose key. ++ * ++ * If NULL, a default value is used. If the empty string "", no ++ * options are used. ++ * If the XKB_DEFAULT_OPTIONS environment variable is set, it is used ++ * as the default. Otherwise the system default is used. ++ */ + const char *options; + }; + +@@ -399,6 +433,11 @@ xkb_keysym_from_name(const char *name, e + * @returns The number of bytes written to the buffer (including the + * terminating byte). If the keysym does not have a Unicode + * representation, returns 0. If the buffer is too small, returns -1. ++ * ++ * Prefer not to use this function on keysyms obtained from an ++ * xkb_state. In this case, use xkb_state_key_get_utf8() instead. ++ * ++ * @sa xkb_state_key_get_utf8() + */ + int + xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size); +@@ -409,6 +448,11 @@ xkb_keysym_to_utf8(xkb_keysym_t keysym, + * @returns The Unicode/UTF-32 representation of keysym, which is also + * compatible with UCS-4. If the keysym does not have a Unicode + * representation, returns 0. ++ * ++ * Prefer not to use this function on keysyms obtained from an ++ * xkb_state. In this case, use xkb_state_key_get_utf32() instead. ++ * ++ * @sa xkb_state_key_get_utf32() + */ + uint32_t + xkb_keysym_to_utf32(xkb_keysym_t keysym); +@@ -681,9 +725,7 @@ xkb_context_set_log_fn(struct xkb_contex + /** Flags for keymap compilation. */ + enum xkb_keymap_compile_flags { + /** Do not apply any flags. */ +- XKB_MAP_COMPILE_NO_FLAGS = 0, +- /** Apparently you can't have empty enums. What a drag. */ +- XKB_MAP_COMPILE_PLACEHOLDER = 0 ++ XKB_KEYMAP_COMPILE_NO_FLAGS = 0 + }; + + /** +@@ -692,13 +734,8 @@ enum xkb_keymap_compile_flags { + * The primary keymap entry point: creates a new XKB keymap from a set of + * RMLVO (Rules + Model + Layouts + Variants + Options) names. + * +- * You should almost certainly be using this and nothing else to create +- * keymaps. +- * + * @param context The context in which to create the keymap. +- * @param names The RMLVO names to use. In xkbcommon versions prior +- * to 0.2.1, this field must be non-NULL. In later +- * versions, passing NULL will use the default keymap. ++ * @param names The RMLVO names to use. See xkb_rule_names. + * @param flags Optional flags for the keymap, or 0. + * + * @returns A keymap compiled according to the RMLVO names, or NULL if +@@ -1159,6 +1196,13 @@ enum xkb_state_component { + * is pressed twice, it should be released twice; etc. Otherwise (e.g. due + * to missed input events), situations like "stuck modifiers" may occur. + * ++ * This function is often used in conjunction with the function ++ * xkb_state_key_get_syms() (or xkb_state_key_get_one_sym()), for example, ++ * when handling a key event. In this case, you should prefer to get the ++ * keysyms *before* updating the key, such that the keysyms reported for ++ * the key event are not affected by the event itself. This is the ++ * conventional behavior. ++ * + * @returns A mask of state components that have changed as a result of + * the update. If nothing in the state has changed, returns 0. + * +@@ -1235,6 +1279,44 @@ xkb_state_key_get_syms(struct xkb_state + const xkb_keysym_t **syms_out); + + /** ++ * Get the Unicode/UTF-8 string obtained from pressing a particular key ++ * in a given keyboard state. ++ * ++ * @param[in] state The keyboard state object. ++ * @param[in] key The keycode of the key. ++ * @param[out] buffer A buffer to write the string into. ++ * @param[in] size Size of the buffer. ++ * ++ * @warning If the buffer passed is too small, the string is truncated ++ * (though still NUL-terminated). ++ * ++ * @returns The number of bytes required for the string, excluding the ++ * NUL byte. If there is nothing to write, returns 0. ++ * ++ * You may check if truncation has occurred by comparing the return value ++ * with the size of @p buffer, similarly to the snprintf(3) function. ++ * You may safely pass NULL and 0 to @p buffer and @p size to find the ++ * required size (without the NUL-byte). ++ * ++ * @memberof xkb_state ++ */ ++int ++xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t key, ++ char *buffer, size_t size); ++ ++/** ++ * Get the Unicode/UTF-32 codepoint obtained from pressing a particular ++ * key in a a given keyboard state. ++ * ++ * @returns The UTF-32 representation for the key, if it consists of only ++ * a single codepoint. Otherwise, returns 0. ++ * ++ * @memberof xkb_state ++ */ ++uint32_t ++xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t key); ++ ++/** + * Get the single keysym obtained from pressing a particular key in a + * given keyboard state. + * +@@ -1485,6 +1567,7 @@ xkb_state_mod_indices_are_active(struct + * index is not valid in the keymap, returns -1. + * + * @sa xkb_state_mod_mask_remove_consumed() ++ * @sa xkb_state_key_get_consumed_mods() + * @memberof xkb_state + */ + int +@@ -1505,6 +1588,17 @@ xkb_state_mod_mask_remove_consumed(struc + xkb_mod_mask_t mask); + + /** ++ * Get the mask of modifiers consumed by translating a given key. ++ * ++ * @returns a mask of the consumed modifiers. ++ * ++ * @sa xkb_state_mod_index_is_consumed() ++ * @memberof xkb_state ++ */ ++xkb_mod_mask_t ++xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key); ++ ++/** + * Test whether a layout is active in a given keyboard state by name. + * + * @returns 1 if the layout is active, 0 if it is not. If no layout with +--- a/src/plugins/platforms/xcb/qxcbkeyboard.h ++++ b/src/plugins/platforms/xcb/qxcbkeyboard.h +@@ -48,10 +48,7 @@ + + #include + #ifndef QT_NO_XKB +-// note: extern won't be needed from libxkbcommon 0.4.1 and above +-extern "C" { + #include +-} + #endif + + #include