From c3a963da1f9e7b1d37e63eedded61da4fbdaaf9a Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 16 Nov 2018 17:07:33 +0100 Subject: src/3rdparty: remove xkbcommon The only reason why we bundled this library ~6 years ago was because it was not available on distributions that we supported at the time, but library was a hard dependency for XCB plugin. See: 2122e731abdb619249df89642c0800640b2fa428 Later more and more projects started to depend on it (compose input context plugin, libinput, mir, wayland). The configuration had become too complex, because some projects used bundled and some used the version from the system. Having libxkbcommon in 3rdparty sources is not necessary anymore, after RHEL 6.6 was removed from the list of supported platforms for Qt 5.12. Ubuntu 16.04 - 0.5.0 Ubuntu 18.04 - 0.8.0 openSUSE 42.3 - 0.6.1 RHEL-7.4 - 0.7.1 This will also simplify further development, e.g. QTBUG-42181 Bumped the minimal required version 0.4.1 -> 0.5.0. The patch also contains a code marked with "TRANSITION HACK", which is temporary needed so we can update the dependent wayland module. [ChangeLog][Third-Party Code] Removed xkbcommon from bundled sources. This library is present on all supported platforms. The minimal required version now is 0.5.0. Task-number: QTBUG-65503 Change-Id: Iec50829bb6f8fbb19f3c4e4ad62e332beb837de5 Reviewed-by: Lars Knoll Reviewed-by: Laszlo Agocs Reviewed-by: Oswald Buddenhagen --- src/plugins/platforminputcontexts/compose/compose.pro | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 2f53c5b416..68bc2c3466 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -9,12 +9,7 @@ SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \ HEADERS += $$PWD/qcomposeplatforminputcontext.h \ $$PWD/generator/qtablegenerator.h \ -# libxkbcommon -!qtConfig(xkbcommon-system) { - include(../../../3rdparty/xkbcommon.pri) -} else { - QMAKE_USE += xkbcommon -} +QMAKE_USE_PRIVATE += xkbcommon include($$OUT_PWD/../../../gui/qtgui-config.pri) -- cgit v1.2.3 From 0c54e0251f27fab85baa03fff7213600419f491c Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 2 Jan 2019 21:54:31 +0100 Subject: ibus: send batched QInputMethodQueryEvent event Change-Id: Idc537a497569d86bb63776934d5e0bbbc39291be Reviewed-by: Mikhail Svetkin Reviewed-by: Lars Knoll --- .../ibus/qibusplatforminputcontext.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 3a54f33832..c0979e7864 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -217,17 +217,14 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q) && (q.testFlag(Qt::ImSurroundingText) || q.testFlag(Qt::ImCursorPosition) || q.testFlag(Qt::ImAnchorPosition))) { - QInputMethodQueryEvent srrndTextQuery(Qt::ImSurroundingText); - QInputMethodQueryEvent cursorPosQuery(Qt::ImCursorPosition); - QInputMethodQueryEvent anchorPosQuery(Qt::ImAnchorPosition); - QCoreApplication::sendEvent(input, &srrndTextQuery); - QCoreApplication::sendEvent(input, &cursorPosQuery); - QCoreApplication::sendEvent(input, &anchorPosQuery); + QInputMethodQueryEvent query(Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition); - QString surroundingText = srrndTextQuery.value(Qt::ImSurroundingText).toString(); - uint cursorPosition = cursorPosQuery.value(Qt::ImCursorPosition).toUInt(); - uint anchorPosition = anchorPosQuery.value(Qt::ImAnchorPosition).toUInt(); + QCoreApplication::sendEvent(input, &query); + + QString surroundingText = query.value(Qt::ImSurroundingText).toString(); + uint cursorPosition = query.value(Qt::ImCursorPosition).toUInt(); + uint anchorPosition = query.value(Qt::ImAnchorPosition).toUInt(); QIBusText text; text.text = surroundingText; -- cgit v1.2.3 From 05bcfb901115eb92820478746cae359d4dc84fbf Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 30 Jan 2019 17:18:04 +0100 Subject: Normalize some SIGNAL/SLOT signatures ...for a minor performance gain. Change-Id: I4bef867055e069926fdc24fa98a6f94b6a0630e2 Reviewed-by: Oliver Wolff --- src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 3a54f33832..ca315840e2 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -593,7 +593,7 @@ void QIBusPlatformInputContext::connectToContextSignals() if (d->context) { connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant))); connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool))); - connect(d->context, SIGNAL(ForwardKeyEvent(uint, uint, uint)), this, SLOT(forwardKeyEvent(uint, uint, uint))); + connect(d->context, SIGNAL(ForwardKeyEvent(uint,uint,uint)), this, SLOT(forwardKeyEvent(uint,uint,uint))); connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint))); connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired())); connect(d->context, SIGNAL(HidePreeditText()), this, SLOT(hidePreeditText())); -- cgit v1.2.3 From 27065bdc50fb3163f41d65ff70653aac8ca19094 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 23 Jan 2019 14:02:38 +0100 Subject: ibus: allow filterEvent() from QWindowSystemEventHandler::sendEvent() The async mode, which is also default mode will recurs if QIBusPlatformInputContext::filterEvent() is called from QWindowSystemEventHandler::sendEvent() callback. The sync mode works fine without this patch. Modes can be toggled via IBUS_ENABLE_SYNC_MODE envvar. Removed redundant #ifndef and renamed one variable to something more meaningful. Change-Id: I8773445cef10212464cff09e3a70487fb38ac3fd Reviewed-by: Takao Fujiwara Reviewed-by: Lars Knoll --- .../ibus/qibusplatforminputcontext.cpp | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index c0979e7864..98362f2116 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -47,7 +47,9 @@ #include #include -#include +#include + +#include #include "qibusproxy.h" #include "qibusproxyportal.h" @@ -419,9 +421,9 @@ bool QIBusPlatformInputContext::filterEvent(const QEvent *event) QDBusPendingReply reply = d->context->ProcessKeyEvent(sym, code - 8, ibusState); if (m_eventFilterUseSynchronousMode || reply.isFinished()) { - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << retval; - return retval; + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << filtered; + return filtered; } Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); @@ -491,23 +493,22 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal const bool isAutoRepeat = args.at(7).toBool(); // copied from QXcbKeyboard::handleKeyEvent() - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval; - if (!retval) { + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << filtered; + if (!filtered) { #ifndef QT_NO_CONTEXTMENU if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu && window != NULL) { const QPoint globalPos = window->screen()->handle()->cursor()->pos(); const QPoint pos = window->mapFromGlobal(globalPos); -#ifndef QT_NO_CONTEXTMENU - QWindowSystemInterface::handleContextMenuEvent(window, false, pos, - globalPos, modifiers); -#endif + QWindowSystemInterfacePrivate::ContextMenuEvent contextMenuEvent(window, false, pos, + globalPos, modifiers); + QGuiApplicationPrivate::processWindowSystemEvent(&contextMenuEvent); } -#endif // QT_NO_CONTEXTMENU - QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, - code, sym, state, string, isAutoRepeat); - +#endif + QWindowSystemInterfacePrivate::KeyEvent keyEvent(window, time, type, qtcode, modifiers, + code, sym, state, string, isAutoRepeat); + QGuiApplicationPrivate::processWindowSystemEvent(&keyEvent); } call->deleteLater(); } -- cgit v1.2.3 From 58cad5caf2064900ae95ef52b521ec8e4b963ff8 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 21 Feb 2019 23:56:58 +0100 Subject: build compose input context plugin not only for XCB platform It can be used by any platform that uses xkbcommon for keyboard input: wayland, eglfs. Change-Id: Iba7d8989f922063cdceb94c1c4bcd8d8e4ae294e Reviewed-by: Giulio Camuffo --- src/plugins/platforminputcontexts/platforminputcontexts.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index ed6b1b8702..68f6792377 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -5,6 +5,6 @@ qtHaveModule(dbus) { !mac:!win32:SUBDIRS += ibus } -qtConfig(xcb): SUBDIRS += compose +qtConfig(xkbcommon): SUBDIRS += compose -- cgit v1.2.3 From 2065bc070dcd1f88a1f5ba3dd6ef0139a9a441ec Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 24 Oct 2014 16:31:48 +0200 Subject: platforminputcontexts: use libxkbcommon compose key API Our implementation of compose table parser was added on Mar, 2013. libxkbcommon added APIs for the same thing in Oct, 2014 (ver: 0.5.0). After removing RHEL 6.6 from the list of supported platforms we were able to move the minimal required libxkbcommon version to 0.5.0. Now we can use the xkbcommon-compose APIs on all supported platforms. With this patch we can drop nearly 1000 lines of maintenance burden. This patch fixes user reported issues with our implementation. Known issues: - Testing revealed that xkbcommon-compose does not support non-utf8 locales, and that is by design - https://github.com/xkbcommon/libxkbcommon/issues/76 Our implementation did work for those locales too, but it is unclear if anyone actually uses non-utf8 locales. It is a corner case (work-arounds existing) and likely a configuration error on the users' system. - Looking at the release notes for versions above 0.6.1, only one issue that stands out. Compose input does not work on system with tr_TR.UTF-8 locale, fixed in 0.7.1. Compose input works fine when using e.g. en_US.UTF-8 locale with Turkish keyboard layout. Note: With Qt 5.13 we have removed Ubuntu 16.04 and openSUSE 42.3 from CI: Ubuntu 16.04 - 0.5.0 openSUSE 42.3 - 0.6.1 CI for Qt 5.13 has: Ubuntu 18.04 - 0.8.0 RHEL-7.4 - 0.7.1 openSUSE 15.0 - 0.8.1 Currently the minimal required libxkbcommon version in src/gui/configure.json is set to 0.5.0, but we could bump it to 0.7.1 to avoid known issues from above, but that is a decision for a separate patch. [ChangeLog][plugins][platforminputcontexts] Now using libxkbcommon-compose APIs for compose key input, instead of Qt's own implementation. Fixes: QTBUG-42181 Fixes: QTBUG-53663 Fixes: QTBUG-48657 Change-Id: I79aafe2bc601293844066e7e5f5eddd3719c6bba Reviewed-by: Giulio Camuffo Reviewed-by: Johan Helsing --- .../platforminputcontexts/compose/compose.pro | 8 +- .../compose/generator/qtablegenerator.cpp | 658 --------------------- .../compose/generator/qtablegenerator.h | 145 ----- .../compose/qcomposeplatforminputcontext.cpp | 289 +++------ .../compose/qcomposeplatforminputcontext.h | 33 +- .../compose/qcomposeplatforminputcontextmain.cpp | 4 +- 6 files changed, 90 insertions(+), 1047 deletions(-) delete mode 100644 src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp delete mode 100644 src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 68bc2c3466..2e2f8600c3 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -3,18 +3,14 @@ TARGET = composeplatforminputcontextplugin QT += core-private gui-private SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \ - $$PWD/qcomposeplatforminputcontext.cpp \ - $$PWD/generator/qtablegenerator.cpp \ + $$PWD/qcomposeplatforminputcontext.cpp -HEADERS += $$PWD/qcomposeplatforminputcontext.h \ - $$PWD/generator/qtablegenerator.h \ +HEADERS += $$PWD/qcomposeplatforminputcontext.h QMAKE_USE_PRIVATE += xkbcommon include($$OUT_PWD/../../../gui/qtgui-config.pri) -DEFINES += X11_PREFIX='\\"$$QMAKE_X11_PREFIX\\"' - OTHER_FILES += $$PWD/compose.json PLUGIN_TYPE = platforminputcontexts diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp deleted file mode 100644 index b5a0a5bbeb..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtablegenerator.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include // LC_CTYPE -#include // strchr, strncmp, etc. -#include // strncasecmp -#include // LC_CTYPE - -static const quint32 SupportedCacheVersion = 1; - -/* - In short on how and why the "Compose" file is cached: - - The "Compose" file is large, for en_US it's likely located at: - /usr/share/X11/locale/en_US.UTF-8/Compose - and it has about 6000 string lines. - Q(Gui)Applications parse this file each time they're created. On modern CPUs - it incurs a 4-10 ms startup penalty of each Qt gui app, on older CPUs - - tens of ms or more. - Since the "Compose" file (almost) never changes using a pre-parsed - cache file instead of the "Compose" file is a good idea to improve Qt5 - application startup time by about 5+ ms (or tens of ms on older CPUs). - - The cache file contains the contents of the QComposeCacheFileHeader struct at the - beginning followed by the pre-parsed contents of the "Compose" file. - - struct QComposeCacheFileHeader stores - (a) The cache version - in the unlikely event that some day one might need - to break compatibility. - (b) The (cache) file size. - (c) The lastModified field tracks if anything changed since the last time - the cache file was saved. - If anything did change then we read the compose file and save (cache) it - in binary/pre-parsed format, which should happen extremely rarely if at all. -*/ - -struct QComposeCacheFileHeader -{ - quint32 cacheVersion; - // The compiler will add 4 padding bytes anyway. - // Reserve them explicitly to possibly use in the future. - quint32 reserved; - quint64 fileSize; - qint64 lastModified; -}; - -// localHostName() copied from qtbase/src/corelib/io/qlockfile_unix.cpp -static QByteArray localHostName() -{ - QByteArray hostName(512, Qt::Uninitialized); - if (gethostname(hostName.data(), hostName.size()) == -1) - return QByteArray(); - hostName.truncate(strlen(hostName.data())); - return hostName; -} - -/* - Reads metadata about the Compose file. Later used to determine if the - compose cache should be updated. The fileSize field will be zero on failure. -*/ -static QComposeCacheFileHeader readFileMetadata(const QString &path) -{ - quint64 fileSize = 0; - qint64 lastModified = 0; - const QByteArray pathBytes = QFile::encodeName(path); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) == 0) { - lastModified = st.st_mtime; - fileSize = st.st_size; - } - QComposeCacheFileHeader info = { 0, 0, fileSize, lastModified }; - return info; -} - -static const QString getCacheFilePath() -{ - QFile machineIdFile("/var/lib/dbus/machine-id"); - QString machineId; - if (machineIdFile.exists()) { - if (machineIdFile.open(QIODevice::ReadOnly)) - machineId = QString::fromLatin1(machineIdFile.readAll().trimmed()); - } - if (machineId.isEmpty()) - machineId = localHostName(); - const QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - return dirPath + QLatin1String("/qt_compose_cache_big_endian_") + machineId; - return dirPath + QLatin1String("/qt_compose_cache_little_endian_") + machineId; -} - -// Returns empty vector on failure -static QVector loadCache(const QComposeCacheFileHeader &composeInfo) -{ - QVector vec; - const QString cacheFilePath = getCacheFilePath(); - QFile inputFile(cacheFilePath); - - if (!inputFile.open(QIODevice::ReadOnly)) - return vec; - QComposeCacheFileHeader cacheInfo; - // use a "buffer" variable to make the line after this one more readable. - char *buffer = reinterpret_cast(&cacheInfo); - - if (inputFile.read(buffer, sizeof cacheInfo) != sizeof cacheInfo) - return vec; - if (cacheInfo.fileSize == 0) - return vec; - // using "!=" just in case someone replaced with a backup that existed before - if (cacheInfo.lastModified != composeInfo.lastModified) - return vec; - if (cacheInfo.cacheVersion != SupportedCacheVersion) - return vec; - const QByteArray pathBytes = QFile::encodeName(cacheFilePath); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) != 0) - return vec; - const off_t fileSize = st.st_size; - if (fileSize > 1024 * 1024 * 5) { - // The cache file size is usually about 150KB, so if its size is over - // say 5MB then somebody inflated the file, abort. - return vec; - } - const off_t bufferSize = fileSize - (sizeof cacheInfo); - const size_t elemSize = sizeof (struct QComposeTableElement); - const int elemCount = bufferSize / elemSize; - const QByteArray ba = inputFile.read(bufferSize); - const char *data = ba.data(); - // Since we know the number of the (many) elements and their size in - // advance calling vector.reserve(..) seems reasonable. - vec.reserve(elemCount); - - for (int i = 0; i < elemCount; i++) { - const QComposeTableElement *elem = - reinterpret_cast(data + (i * elemSize)); - vec.push_back(*elem); - } - return vec; -} - -// Returns true on success, false otherwise. -static bool saveCache(const QComposeCacheFileHeader &info, const QVector &vec) -{ - const QString filePath = getCacheFilePath(); -#if QT_CONFIG(temporaryfile) - QSaveFile outputFile(filePath); -#else - QFile outputFile(filePath); -#endif - if (!outputFile.open(QIODevice::WriteOnly)) - return false; - const char *data = reinterpret_cast(&info); - - if (outputFile.write(data, sizeof info) != sizeof info) - return false; - data = reinterpret_cast(vec.constData()); - const qint64 size = vec.size() * (sizeof (struct QComposeTableElement)); - - if (outputFile.write(data, size) != size) - return false; -#if QT_CONFIG(temporaryfile) - return outputFile.commit(); -#else - return true; -#endif -} - -TableGenerator::TableGenerator() : m_state(NoErrors), - m_systemComposeDir(QString()) -{ - initPossibleLocations(); - QString composeFilePath = findComposeFile(); -#ifdef DEBUG_GENERATOR -// don't use cache when in debug mode. - if (!composeFilePath.isEmpty()) - qDebug() << "Using Compose file from: " << composeFilePath; -#else - QComposeCacheFileHeader fileInfo = readFileMetadata(composeFilePath); - if (fileInfo.fileSize != 0) - m_composeTable = loadCache(fileInfo); -#endif - if (m_composeTable.isEmpty() && cleanState()) { - if (composeFilePath.isEmpty()) { - m_state = MissingComposeFile; - } else { - QFile composeFile(composeFilePath); - composeFile.open(QIODevice::ReadOnly); - parseComposeFile(&composeFile); - orderComposeTable(); - if (m_composeTable.isEmpty()) { - m_state = EmptyTable; -#ifndef DEBUG_GENERATOR -// don't save cache when in debug mode - } else { - fileInfo.cacheVersion = SupportedCacheVersion; - saveCache(fileInfo, m_composeTable); -#endif - } - } - } -#ifdef DEBUG_GENERATOR - printComposeTable(); -#endif -} - -void TableGenerator::initPossibleLocations() -{ - // Compose files come as a part of Xlib library. Xlib doesn't provide - // a mechanism how to retrieve the location of these files reliably, since it was - // never meant for external software to parse compose tables directly. Best we - // can do is to hardcode search paths. To add an extra system path use - // the QTCOMPOSE environment variable - m_possibleLocations.reserve(7); - if (qEnvironmentVariableIsSet("QTCOMPOSE")) - m_possibleLocations.append(QString::fromLocal8Bit(qgetenv("QTCOMPOSE"))); - m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/share/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/lib/X11/locale")); -} - -QString TableGenerator::findComposeFile() -{ - // check if XCOMPOSEFILE points to a Compose file - if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) { - const QString path = QFile::decodeName(qgetenv("XCOMPOSEFILE")); - if (QFile::exists(path)) - return path; - else - qWarning("$XCOMPOSEFILE doesn't point to an existing file"); - } - - // check if user’s home directory has a file named .XCompose - if (cleanState()) { - QString path = qgetenv("HOME") + QLatin1String("/.XCompose"); - if (QFile::exists(path)) - return path; - } - - // check for the system provided compose files - if (cleanState()) { - QString table = composeTableForLocale(); - if (cleanState()) { - if (table.isEmpty()) - // no table mappings for the system's locale in the compose.dir - m_state = UnsupportedLocale; - else { - QString path = QDir(systemComposeDir()).filePath(table); - if (QFile::exists(path)) - return path; - } - } - } - return QString(); -} - -QString TableGenerator::composeTableForLocale() -{ - QByteArray loc = locale().toUpper().toUtf8(); - QString table = readLocaleMappings(loc); - if (table.isEmpty()) - table = readLocaleMappings(readLocaleAliases(loc)); - return table; -} - -bool TableGenerator::findSystemComposeDir() -{ - bool found = false; - for (int i = 0; i < m_possibleLocations.size(); ++i) { - QString path = m_possibleLocations.at(i); - if (QFile::exists(path + QLatin1String("/compose.dir"))) { - m_systemComposeDir = path; - found = true; - break; - } - } - - if (!found) { - // should we ask to report this in the qt bug tracker? - m_state = UnknownSystemComposeDir; - qWarning("Qt Warning: Could not find a location of the system's Compose files. " - "Consider setting the QTCOMPOSE environment variable."); - } - - return found; -} - -QString TableGenerator::systemComposeDir() -{ - if (m_systemComposeDir.isNull() - && !findSystemComposeDir()) { - return QLatin1String("$QTCOMPOSE"); - } - - return m_systemComposeDir; -} - -QString TableGenerator::locale() const -{ - char *name = setlocale(LC_CTYPE, (char *)0); - return QLatin1String(name); -} - -QString TableGenerator::readLocaleMappings(const QByteArray &locale) -{ - QString file; - if (locale.isEmpty()) - return file; - - QFile mappings(systemComposeDir() + QLatin1String("/compose.dir")); - if (mappings.open(QIODevice::ReadOnly)) { - const int localeNameLength = locale.size(); - const char * const localeData = locale.constData(); - - char l[1024]; - // formating of compose.dir has some inconsistencies - while (!mappings.atEnd()) { - int read = mappings.readLine(l, sizeof(l)); - if (read <= 0) - break; - - char *line = l; - if (*line >= 'a' && *line <= 'z') { - // file name - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - const char * const composeFileNameEnd = line; - *line = '\0'; - ++line; - - // locale name - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char * const lc = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = '\0'; - if (localeNameLength == (line - lc) && !strncasecmp(lc, localeData, line - lc)) { - file = QString::fromLocal8Bit(l, composeFileNameEnd - l); - break; - } - } - } - mappings.close(); - } - return file; -} - -QByteArray TableGenerator::readLocaleAliases(const QByteArray &locale) -{ - QFile aliases(systemComposeDir() + QLatin1String("/locale.alias")); - QByteArray fullLocaleName; - if (aliases.open(QIODevice::ReadOnly)) { - while (!aliases.atEnd()) { - char l[1024]; - int read = aliases.readLine(l, sizeof(l)); - char *line = l; - if (read && ((*line >= 'a' && *line <= 'z') || - (*line >= 'A' && *line <= 'Z'))) { - const char *alias = line; - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - *line = 0; - if (locale.size() == (line - alias) - && !strncasecmp(alias, locale.constData(), line - alias)) { - // found a match for alias, read the real locale name - ++line; - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char *fullName = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = 0; - fullLocaleName = fullName; -#ifdef DEBUG_GENERATOR - qDebug() << "Alias for: " << alias << "is: " << fullLocaleName; - break; -#endif - } - } - } - aliases.close(); - } - return fullLocaleName; -} - -bool TableGenerator::processFile(const QString &composeFileName) -{ - QFile composeFile(composeFileName); - if (composeFile.open(QIODevice::ReadOnly)) { - parseComposeFile(&composeFile); - return true; - } - qWarning() << QString(QLatin1String("Qt Warning: Compose file: \"%1\" can't be found")) - .arg(composeFile.fileName()); - return false; -} - -TableGenerator::~TableGenerator() -{ -} - -QVector TableGenerator::composeTable() const -{ - return m_composeTable; -} - -void TableGenerator::parseComposeFile(QFile *composeFile) -{ -#ifdef DEBUG_GENERATOR - qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName(); -#endif - - char line[1024]; - while (!composeFile->atEnd()) { - composeFile->readLine(line, sizeof(line)); - if (*line == '<') - parseKeySequence(line); - else if (!strncmp(line, "include", 7)) - parseIncludeInstruction(QString::fromLocal8Bit(line)); - } - - composeFile->close(); -} - -void TableGenerator::parseIncludeInstruction(QString line) -{ - // Parse something that looks like: - // include "/usr/share/X11/locale/en_US.UTF-8/Compose" - QString quote = QStringLiteral("\""); - line.remove(0, line.indexOf(quote) + 1); - line.chop(line.length() - line.indexOf(quote)); - - // expand substitutions if present - line.replace(QLatin1String("%H"), QString(qgetenv("HOME"))); - line.replace(QLatin1String("%L"), systemComposeDir() + QLatin1Char('/') + composeTableForLocale()); - line.replace(QLatin1String("%S"), systemComposeDir()); - - processFile(line); -} - -ushort TableGenerator::keysymToUtf8(quint32 sym) -{ - QByteArray chars; - int bytes; - chars.resize(8); - bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); - if (bytes == -1) - qWarning("TableGenerator::keysymToUtf8 - buffer too small"); - - chars.resize(bytes-1); - -#ifdef DEBUG_GENERATOR - QTextCodec *codec = QTextCodec::codecForLocale(); - qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16)) - .arg(codec->toUnicode(chars)); -#endif - return QString::fromUtf8(chars).at(0).unicode(); -} - -static inline int fromBase8(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - if (*s < '0' || *s > '7') - return 0; - result *= 8; - result += *s - '0'; - ++s; - } - return result; -} - -static inline int fromBase16(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - result *= 16; - if (*s >= '0' && *s <= '9') - result += *s - '0'; - else if (*s >= 'a' && *s <= 'f') - result += *s - 'a' + 10; - else if (*s >= 'A' && *s <= 'F') - result += *s - 'A' + 10; - else - return 0; - ++s; - } - return result; -} - -void TableGenerator::parseKeySequence(char *line) -{ - // we are interested in the lines with the following format: - // : "♬" U266c # BEAMED SIXTEENTH NOTE - char *keysEnd = strchr(line, ':'); - if (!keysEnd) - return; - - QComposeTableElement elem; - // find the composed value - strings may be direct text encoded in the locale - // for which the compose file is to be used, or an escaped octal or hexadecimal - // character code. Octal codes are specified as "\123" and hexadecimal codes as "\0x123a". - char *composeValue = strchr(keysEnd, '"'); - if (!composeValue) - return; - ++composeValue; - - char *composeValueEnd = strchr(composeValue, '"'); - if (!composeValueEnd) - return; - - // if composed value is a quotation mark adjust the end pointer - if (composeValueEnd[1] == '"') - ++composeValueEnd; - - if (*composeValue == '\\' && composeValue[1] >= '0' && composeValue[1] <= '9') { - // handle octal and hex code values - char detectBase = composeValue[2]; - if (detectBase == 'x') { - // hexadecimal character code - elem.value = keysymToUtf8(fromBase16(composeValue + 3, composeValueEnd)); - } else { - // octal character code - elem.value = keysymToUtf8(fromBase8(composeValue + 1, composeValueEnd)); - } - } else { - // handle direct text encoded in the locale - if (*composeValue == '\\') - ++composeValue; - elem.value = QString::fromLocal8Bit(composeValue, composeValueEnd - composeValue).at(0).unicode(); - ++composeValue; - } - -#ifdef DEBUG_GENERATOR - // find the comment - elem.comment = QString::fromLocal8Bit(composeValueEnd + 1).trimmed(); -#endif - - // find the key sequence and convert to X11 keysym - char *k = line; - const char *kend = keysEnd; - - for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - // find the next pair of angle brackets and get the contents within - while (k < kend && *k != '<') - ++k; - char *sym = ++k; - while (k < kend && *k != '>') - ++k; - *k = '\0'; - if (k < kend) { - elem.keys[i] = xkb_keysym_from_name(sym, (xkb_keysym_flags)0); - if (elem.keys[i] == XKB_KEY_NoSymbol) { - if (!strcmp(sym, "dead_inverted_breve")) - elem.keys[i] = XKB_KEY_dead_invertedbreve; - else if (!strcmp(sym, "dead_double_grave")) - elem.keys[i] = XKB_KEY_dead_doublegrave; -#ifdef DEBUG_GENERATOR - else - qWarning() << QString("Qt Warning - invalid keysym: %1").arg(sym); -#endif - } - } else { - elem.keys[i] = 0; - } - } - m_composeTable.append(elem); -} - -void TableGenerator::printComposeTable() const -{ -#ifdef DEBUG_GENERATOR -# ifndef QT_NO_DEBUG_STREAM - if (m_composeTable.isEmpty()) - return; - - QDebug ds = qDebug() << "output:\n"; - ds.nospace(); - const int tableSize = m_composeTable.size(); - for (int i = 0; i < tableSize; ++i) { - const QComposeTableElement &elem = m_composeTable.at(i); - ds << "{ {"; - for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) { - ds << hex << showbase << elem.keys[j] << ", "; - } - ds << "}, " << hex << showbase << elem.value << ", \"\" }, // " << elem.comment << " \n"; - } -# endif -#endif -} - -void TableGenerator::orderComposeTable() -{ - // Stable-sorting to ensure that the item that appeared before the other in the - // original container will still appear first after the sort. This property is - // needed to handle the cases when user re-defines already defined key sequence - std::stable_sort(m_composeTable.begin(), m_composeTable.end(), ByKeys()); -} - diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h deleted file mode 100644 index 4f58358f4e..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTABLEGENERATOR_H -#define QTABLEGENERATOR_H - -#include -#include -#include -#include - -#include - -static Q_CONSTEXPR int QT_KEYSEQUENCE_MAX_LEN = 6; - -//#define DEBUG_GENERATOR - -/* Whenever QComposeTableElement gets modified supportedCacheVersion - from qtablegenerator.cpp must be bumped. */ -struct QComposeTableElement { - uint keys[QT_KEYSEQUENCE_MAX_LEN]; - uint value; -#ifdef DEBUG_GENERATOR - QString comment; -#endif -}; - -#ifndef DEBUG_GENERATOR -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(QComposeTableElement, Q_PRIMITIVE_TYPE); -QT_END_NAMESPACE -#endif - -struct ByKeys -{ - using uint_array = uint[QT_KEYSEQUENCE_MAX_LEN]; - using result_type = bool; - - bool operator()(const uint_array &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return std::lexicographical_compare(lhs, lhs + QT_KEYSEQUENCE_MAX_LEN, - rhs, rhs + QT_KEYSEQUENCE_MAX_LEN); - } - - bool operator()(const uint_array &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs, rhs.keys); - } - - bool operator()(const QComposeTableElement &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs); - } - - bool operator()(const QComposeTableElement &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs.keys); - } -}; - -class TableGenerator -{ - -public: - enum TableState - { - UnsupportedLocale, - EmptyTable, - UnknownSystemComposeDir, - MissingComposeFile, - NoErrors - }; - - TableGenerator(); - ~TableGenerator(); - - void parseComposeFile(QFile *composeFile); - void printComposeTable() const; - void orderComposeTable(); - - QVector composeTable() const; - TableState tableState() const { return m_state; } - -protected: - bool processFile(const QString &composeFileName); - void parseKeySequence(char *line); - void parseIncludeInstruction(QString line); - - QString findComposeFile(); - bool findSystemComposeDir(); - QString systemComposeDir(); - QString composeTableForLocale(); - - ushort keysymToUtf8(quint32 sym); - - QString readLocaleMappings(const QByteArray &locale); - QByteArray readLocaleAliases(const QByteArray &locale); - void initPossibleLocations(); - bool cleanState() const { return m_state == NoErrors; } - QString locale() const; - -private: - QVector m_composeTable; - TableState m_state; - QString m_systemComposeDir; - QList m_possibleLocations; -}; - -#endif // QTABLEGENERATOR_H diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 81a730232c..6b9687c22d 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -36,131 +36,100 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include "qcomposeplatforminputcontext.h" #include #include -#include -#include +#include QT_BEGIN_NAMESPACE -//#define DEBUG_COMPOSING +Q_LOGGING_CATEGORY(lcXkbCompose, "qt.xkb.compose") -static const int ignoreKeys[] = { - Qt::Key_Shift, - Qt::Key_Control, - Qt::Key_Meta, - Qt::Key_Alt, - Qt::Key_CapsLock, - Qt::Key_Super_L, - Qt::Key_Super_R, - Qt::Key_Hyper_L, - Qt::Key_Hyper_R, - Qt::Key_Mode_switch -}; +QComposeInputContext::QComposeInputContext() +{ + setObjectName(QStringLiteral("QComposeInputContext")); + qCDebug(lcXkbCompose, "using xkb compose input context"); +} -static const int composingKeys[] = { - Qt::Key_Multi_key, - Qt::Key_Dead_Grave, - Qt::Key_Dead_Acute, - Qt::Key_Dead_Circumflex, - Qt::Key_Dead_Tilde, - Qt::Key_Dead_Macron, - Qt::Key_Dead_Breve, - Qt::Key_Dead_Abovedot, - Qt::Key_Dead_Diaeresis, - Qt::Key_Dead_Abovering, - Qt::Key_Dead_Doubleacute, - Qt::Key_Dead_Caron, - Qt::Key_Dead_Cedilla, - Qt::Key_Dead_Ogonek, - Qt::Key_Dead_Iota, - Qt::Key_Dead_Voiced_Sound, - Qt::Key_Dead_Semivoiced_Sound, - Qt::Key_Dead_Belowdot, - Qt::Key_Dead_Hook, - Qt::Key_Dead_Horn, - Qt::Key_Dead_Stroke, - Qt::Key_Dead_Abovecomma, - Qt::Key_Dead_Abovereversedcomma, - Qt::Key_Dead_Doublegrave, - Qt::Key_Dead_Belowring, - Qt::Key_Dead_Belowmacron, - Qt::Key_Dead_Belowcircumflex, - Qt::Key_Dead_Belowtilde, - Qt::Key_Dead_Belowbreve, - Qt::Key_Dead_Belowdiaeresis, - Qt::Key_Dead_Invertedbreve, - Qt::Key_Dead_Belowcomma, - Qt::Key_Dead_Currency, - Qt::Key_Dead_a, - Qt::Key_Dead_A, - Qt::Key_Dead_e, - Qt::Key_Dead_E, - Qt::Key_Dead_i, - Qt::Key_Dead_I, - Qt::Key_Dead_o, - Qt::Key_Dead_O, - Qt::Key_Dead_u, - Qt::Key_Dead_U, - Qt::Key_Dead_Small_Schwa, - Qt::Key_Dead_Capital_Schwa, - Qt::Key_Dead_Greek, - Qt::Key_Dead_Lowline, - Qt::Key_Dead_Aboveverticalline, - Qt::Key_Dead_Belowverticalline, - Qt::Key_Dead_Longsolidusoverlay -}; +QComposeInputContext::~QComposeInputContext() +{ + xkb_compose_state_unref(m_composeState); + xkb_compose_table_unref(m_composeTable); +} -QComposeInputContext::QComposeInputContext() - : m_tableState(TableGenerator::EmptyTable) - , m_compositionTableInitialized(false) +void QComposeInputContext::ensureInitialized() { - clearComposeBuffer(); + if (m_initialized) + return; + + if (!m_XkbContext) { + qCWarning(lcXkbCompose) << "error: xkb context has not been set on" << metaObject()->className(); + return; + } + + m_initialized = true; + const char *const locale = setlocale(LC_CTYPE, ""); + qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale; + + m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + if (m_composeTable) + m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + + if (!m_composeTable) { + qCWarning(lcXkbCompose, "failed to create compose table"); + return; + } + if (!m_composeState) { + qCWarning(lcXkbCompose, "failed to create compose state"); + return; + } } bool QComposeInputContext::filterEvent(const QEvent *event) { - const QKeyEvent *keyEvent = (const QKeyEvent *)event; - // should pass only the key presses - if (keyEvent->type() != QEvent::KeyPress) { + auto keyEvent = static_cast(event); + if (keyEvent->type() != QEvent::KeyPress) return false; - } - // if there were errors when generating the compose table input - // context should not try to filter anything, simply return false - if (m_compositionTableInitialized && (m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) + if (!inputMethodAccepted()) return false; - int keyval = keyEvent->key(); - int keysym = 0; + // lazy initialization - we don't want to do this on an app startup + ensureInitialized(); - if (ignoreKey(keyval)) + if (!m_composeTable || !m_composeState) return false; - if (!composeKey(keyval) && keyEvent->text().isEmpty()) - return false; + xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey()); - keysym = keyEvent->nativeVirtualKey(); + switch (xkb_compose_state_get_status(m_composeState)) { + case XKB_COMPOSE_COMPOSING: + return true; + case XKB_COMPOSE_CANCELLED: + reset(); + return false; + case XKB_COMPOSE_COMPOSED: + { + const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0); + QVarLengthArray buffer(size + 1); + xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size()); + QString composedText = QString::fromUtf8(buffer.constData()); - int nCompose = 0; - while (nCompose < QT_KEYSEQUENCE_MAX_LEN && m_composeBuffer[nCompose] != 0) - nCompose++; + QInputMethodEvent event; + event.setCommitString(composedText); + QCoreApplication::sendEvent(m_focusObject, &event); - if (nCompose == QT_KEYSEQUENCE_MAX_LEN) { reset(); - nCompose = 0; - } - - m_composeBuffer[nCompose] = keysym; - // check sequence - if (checkComposeTable()) return true; - - return false; + } + case XKB_COMPOSE_NOTHING: + return false; + default: + Q_UNREACHABLE(); + return false; + } } bool QComposeInputContext::isValid() const @@ -175,7 +144,8 @@ void QComposeInputContext::setFocusObject(QObject *object) void QComposeInputContext::reset() { - clearComposeBuffer(); + if (m_composeState) + xkb_compose_state_reset(m_composeState); } void QComposeInputContext::update(Qt::InputMethodQueries q) @@ -183,125 +153,4 @@ void QComposeInputContext::update(Qt::InputMethodQueries q) QPlatformInputContext::update(q); } -static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs) -{ - return std::equal(lhs.keys, lhs.keys + QT_KEYSEQUENCE_MAX_LEN, - QT_MAKE_CHECKED_ARRAY_ITERATOR(rhs.keys, QT_KEYSEQUENCE_MAX_LEN)); -} - -bool QComposeInputContext::checkComposeTable() -{ - if (!m_compositionTableInitialized) { - TableGenerator reader; - m_tableState = reader.tableState(); - - m_compositionTableInitialized = true; - if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) { - m_composeTable = reader.composeTable(); - } else { -#ifdef DEBUG_COMPOSING - qDebug( "### FAILED_PARSING ###" ); -#endif - // if we have errors, don' try to look things up anyways. - reset(); - return false; - } - } - Q_ASSERT(!m_composeTable.isEmpty()); - QVector::const_iterator it = - std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, ByKeys()); - - // prevent dereferencing an 'end' iterator, which would result in a crash - if (it == m_composeTable.constEnd()) - it -= 1; - - QComposeTableElement elem = *it; - // would be nicer if qLowerBound had API that tells if the item was actually found - if (m_composeBuffer[0] != elem.keys[0]) { -#ifdef DEBUG_COMPOSING - qDebug( "### no match ###" ); -#endif - reset(); - return false; - } - // check if compose buffer is matched - for (int i=0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - - // check if partial match - if (m_composeBuffer[i] == 0 && elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### partial match ###"); -#endif - return true; - } - - if (m_composeBuffer[i] != elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### different entry ###"); -#endif - reset(); - return i != 0; - } - } -#ifdef DEBUG_COMPOSING - qDebug("### match exactly ###"); -#endif - - // check if the key sequence is overwriten - see the comment in - // TableGenerator::orderComposeTable() - int next = 1; - do { - // if we are at the end of the table, then we have nothing to do here - if (it + next != m_composeTable.constEnd()) { - QComposeTableElement nextElem = *(it + next); - if (isDuplicate(elem, nextElem)) { - elem = nextElem; - next++; - continue; - } else { - break; - } - } - break; - } while (true); - - commitText(elem.value); - reset(); - - return true; -} - -void QComposeInputContext::commitText(uint character) const -{ - QInputMethodEvent event; - event.setCommitString(QChar(character)); - QCoreApplication::sendEvent(m_focusObject, &event); -} - -bool QComposeInputContext::ignoreKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(ignoreKeys) / sizeof(ignoreKeys[0])); i++) - if (keyval == ignoreKeys[i]) - return true; - - return false; -} - -bool QComposeInputContext::composeKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(composingKeys) / sizeof(composingKeys[0])); i++) - if (keyval == composingKeys[i]) - return true; - - return false; -} - -void QComposeInputContext::clearComposeBuffer() -{ - for (uint i=0; i < (sizeof(m_composeBuffer) / sizeof(int)); i++) - m_composeBuffer[i] = 0; -} - -QComposeInputContext::~QComposeInputContext() {} - QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h index 4830959665..b1de1b1094 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -36,24 +36,24 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H #define QCOMPOSEPLATFORMINPUTCONTEXT_H -#include +#include -#include +#include -#include "generator/qtablegenerator.h" +#include QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcXkbCompose) + class QEvent; class QComposeInputContext : public QPlatformInputContext { Q_OBJECT - public: QComposeInputContext(); ~QComposeInputContext(); @@ -62,21 +62,22 @@ public: void setFocusObject(QObject *object) override; void reset() override; void update(Qt::InputMethodQueries) override; + bool filterEvent(const QEvent *event) override; + // This invokable is called from QXkbCommon::setXkbContext(). + Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; } + protected: - void clearComposeBuffer(); - bool ignoreKey(int keyval) const; - bool composeKey(int keyval) const; - bool checkComposeTable(); - void commitText(uint character) const; + void ensureInitialized(); private: - QObject *m_focusObject; - QVector m_composeTable; - uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN]; - TableGenerator::TableState m_tableState; - bool m_compositionTableInitialized; + bool m_initialized = false; + xkb_context *m_context = nullptr; + xkb_compose_table *m_composeTable = nullptr; + xkb_compose_state *m_composeState = nullptr; + QObject *m_focusObject = nullptr; + struct xkb_context *m_XkbContext = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp index 6b33df65b9..d062d4fd6a 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -61,7 +61,7 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString & if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0 || system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0) return new QComposeInputContext; - return 0; + return nullptr; } QT_END_NAMESPACE -- cgit v1.2.3 From f792fed2ff519ffac1436e41e47cc0504d253a77 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 5 Mar 2019 14:25:45 +0100 Subject: XCB/libxkbcommon input context: Fix crash when invalid local is set Fall back to querying the locale. Fixes: QTBUG-74216 Change-Id: Ibd60572454741e64f649ecc3e37f593a8e2b2bda Reviewed-by: Edward Welbourne --- .../platforminputcontexts/compose/qcomposeplatforminputcontext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 6b9687c22d..57fe7c2fa2 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -70,7 +70,9 @@ void QComposeInputContext::ensureInitialized() } m_initialized = true; - const char *const locale = setlocale(LC_CTYPE, ""); + const char *locale = setlocale(LC_CTYPE, ""); + if (!locale) + locale = setlocale(LC_CTYPE, nullptr); qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale; m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); -- cgit v1.2.3 From 41e7b71c410b77a81d09d3cc2e169ffd7975b4d2 Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Tue, 12 Mar 2019 11:46:26 +0100 Subject: More nullptr usage in headers Diff generated by running clang-tidy's modernize-use-nullptr checker on the CMake-based Qt version. Skipping src/3rdparty, examples/, tests/ Change-Id: Ib182074e2e2fd52f63093f73b3e2e4c0cb7af188 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann --- src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h | 2 +- src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h | 6 +++--- src/plugins/platforminputcontexts/ibus/qibusproxy.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h index 47a40ab8c2..396a213aaa 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h @@ -31,7 +31,7 @@ public: { return "org.freedesktop.IBus.InputContext"; } public: - QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); ~QIBusInputContextProxy(); diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h index d4daea2eb3..8e7b8df120 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -59,9 +59,9 @@ class QIBusFilterEventWatcher: public QDBusPendingCallWatcher { public: explicit QIBusFilterEventWatcher(const QDBusPendingCall &call, - QObject *parent = 0, - QWindow *window = 0, - const Qt::KeyboardModifiers modifiers = 0, + QObject *parent = nullptr, + QWindow *window = nullptr, + const Qt::KeyboardModifiers modifiers = nullptr, const QVariantList arguments = QVariantList()) : QDBusPendingCallWatcher(call, parent) , m_window(window) diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.h b/src/plugins/platforminputcontexts/ibus/qibusproxy.h index 839e972c34..c9876deebf 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusproxy.h +++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.h @@ -35,7 +35,7 @@ public: { return QStringLiteral("org.freedesktop.DBus.Properties"); } public: - QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); ~QIBusProxy(); -- cgit v1.2.3 From 9b6222598c990512c78bd42f55d7d6dc635c8b48 Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Mon, 25 Mar 2019 17:09:28 +0900 Subject: Calculate Qt::Key from keysym for IBus ForwardKeyEvent signal QKeyEvent instance requires Qt::Key but currently X11 keysym is assigned and the IBus QT module forwards the wrong key events. Now QXkbCommon::keysymToQtKey() can generate Qt::Key from keysym and forward the correct key events. Change-Id: I25f0a9e9319b4a5f42847f8592ad3a30f6c9349d Reviewed-by: Gatis Paeglis --- src/plugins/platforminputcontexts/ibus/ibus.pro | 2 +- .../ibus/qibusplatforminputcontext.cpp | 14 ++++++++++---- .../platforminputcontexts/platforminputcontexts.pro | 11 ++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'src/plugins/platforminputcontexts') diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro index 52836bb8b6..9ba2297e38 100644 --- a/src/plugins/platforminputcontexts/ibus/ibus.pro +++ b/src/plugins/platforminputcontexts/ibus/ibus.pro @@ -1,6 +1,6 @@ TARGET = ibusplatforminputcontextplugin -QT += dbus gui-private +QT += dbus gui-private xkbcommon_support-private SOURCES += $$PWD/qibusplatforminputcontext.cpp \ $$PWD/qibusproxy.cpp \ $$PWD/qibusproxyportal.cpp \ diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 7e66439ea7..f2429f24ff 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -51,6 +51,8 @@ #include +#include + #include "qibusproxy.h" #include "qibusproxyportal.h" #include "qibusinputcontextproxy.h" @@ -335,14 +337,12 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint if (!input) return; - if (debug) - qDebug() << "forwardKeyEvent" << keyval << keycode << state; - QEvent::Type type = QEvent::KeyPress; if (state & IBUS_RELEASE_MASK) type = QEvent::KeyRelease; state &= ~IBUS_RELEASE_MASK; + keycode += 8; Qt::KeyboardModifiers modifiers = Qt::NoModifier; if (state & IBUS_SHIFT_MASK) @@ -354,7 +354,13 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint if (state & IBUS_META_MASK) modifiers |= Qt::MetaModifier; - QKeyEvent event(type, keyval, modifiers, QString(keyval)); + int qtcode = QXkbCommon::keysymToQtKey(keyval, modifiers); + QString text = QXkbCommon::lookupStringNoKeysymTransformations(keyval); + + if (debug) + qDebug() << "forwardKeyEvent" << keyval << keycode << state << modifiers << qtcode << text; + + QKeyEvent event(type, qtcode, modifiers, keycode, keyval, state, text); QCoreApplication::sendEvent(input, &event); } diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index 68f6792377..56a39a49e7 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -1,10 +1,11 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -qtHaveModule(dbus) { -!mac:!win32:SUBDIRS += ibus -} - -qtConfig(xkbcommon): SUBDIRS += compose +qtConfig(xkbcommon) { + SUBDIRS += compose + qtHaveModule(dbus) { + !macos:!win32:SUBDIRS += ibus + } +} -- cgit v1.2.3