diff --git a/plugin-kbindicator/CMakeLists.txt b/plugin-kbindicator/CMakeLists.txt index 29a208f9d..b30cfddd7 100644 --- a/plugin-kbindicator/CMakeLists.txt +++ b/plugin-kbindicator/CMakeLists.txt @@ -31,9 +31,29 @@ set(LIBRARIES find_package(XCB REQUIRED COMPONENTS xcb xcb-xkb) find_package(XKBCommon REQUIRED COMPONENTS XKBCommon X11) +find_package(X11 REQUIRED) find_package(Qt5 ${QT_MINIMUM_VERSION} REQUIRED COMPONENTS X11Extras Xml) -include_directories(${XCB_INCLUDE_DIRS}) +if(NOT X11_Xkbfile_FOUND) + MESSAGE(FATAL_ERROR "'libxkbfile' not found. Aborting") +endif() + +find_package(PkgConfig REQUIRED) +execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=xkb_base xkeyboard-config + OUTPUT_VARIABLE XKB_RULES_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if(NOT EXISTS "${XKB_RULES_DIR}") + message(FATAL_ERROR "Couldn't find XKB rules location: \"${XKB_RULES_DIR}\".") +endif() + +message(STATUS "X11_xkbfile_INCLUDE_PATH: ${X11_xkbfile_INCLUDE_PATH}") +message(STATUS "X11_INCLUDE_DIR: ${X11_INCLUDE_DIR}") + +include_directories( + ${XCB_INCLUDE_DIRS} + ${X11_xkbfile_INCLUDE_PATH} +) set(HEADERS ${HEADERS} @@ -48,11 +68,13 @@ set(SOURCES set(LIBRARIES ${LIBRARIES} ${XCB_LIBRARIES} + ${X11_xkbfile_LIB} XKBCommon::XKBCommon XKBCommon::X11 Qt5::Xml ) -add_definitions(-DX11_ENABLED) +add_definitions(-DX11_ENABLED -DXKB_RULES_DIR=\"${XKB_RULES_DIR}\") + BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-kbindicator/src/x11/kbdlayout.cpp b/plugin-kbindicator/src/x11/kbdlayout.cpp index 90c2b0bcc..981542f36 100644 --- a/plugin-kbindicator/src/x11/kbdlayout.cpp +++ b/plugin-kbindicator/src/x11/kbdlayout.cpp @@ -28,11 +28,15 @@ #include #include #include +#include #include #include "kbdlayout.h" #include #include +#include +#include +#include // Note: We need to override "explicit" as this is a C++ keyword. But it is // used as variable name in xkb.h. This is causing a failure in C++ compile @@ -45,6 +49,56 @@ #include "../kbdinfo.h" #include "../controls.h" +static QString xkbRulesDir(); +static QString xkbRulesFile(); +static QString xkbRulesName(); +static void _lxqt_xkb_free_var_defs(XkbRF_VarDefsRec *var_defs); + +static QString xkbRulesDir() +{ + return QStringLiteral(XKB_RULES_DIR); +} + +static QString xkbRulesFile() +{ + QString rulesFile; + const QString rules = xkbRulesName(); + const QString xkbDir = xkbRulesDir(); + if (!rules.isEmpty()) { + rulesFile = QStringLiteral("%1/rules/%2.xml").arg(xkbDir, rules); + } else { // default + rulesFile = QStringLiteral("%1/rules/evdev.xml").arg(xkbDir); + } + return rulesFile; +} + +static QString xkbRulesName() +{ + if (!QX11Info::isPlatformX11()) { + return QString(); + } + XkbRF_VarDefsRec v{}; + char *file = nullptr; + + if (XkbRF_GetNamesProp(QX11Info::display(), &file, &v) && file != nullptr) { + const QString name = QString::fromUtf8(file); + XFree(file); + _lxqt_xkb_free_var_defs(&v); + return name; + } + return {}; +} + +static void _lxqt_xkb_free_var_defs(XkbRF_VarDefsRec *var_defs) +{ + if (var_defs == nullptr) + return; + + free(static_cast(var_defs->model)); + free(static_cast(var_defs->layout)); + free(static_cast(var_defs->variant)); + free(static_cast(var_defs->options)); +} namespace pimpl { struct LangInfo @@ -245,10 +299,11 @@ class X11Kbd: public QAbstractNativeEventFilter static LangInfo def{QStringLiteral("Unknown"), QStringLiteral("??"), QStringLiteral("None")}; static QHash names; if (names.empty()){ - if(QFile::exists(QStringLiteral("/usr/share/X11/xkb/rules/evdev.xml"))){ + const QString rulesFile{xkbRulesFile()}; + if(QFile::exists(rulesFile)){ QDomDocument doc; - QFile file(QStringLiteral("/usr/share/X11/xkb/rules/evdev.xml")); + QFile file(rulesFile); if (file.open(QIODevice::ReadOnly)){ if (doc.setContent(&file)) { QDomElement docElem = doc.documentElement();