diff --git a/config_help.txt b/config_help.txt index f61601ec7a..3e2c0c61b0 100644 --- a/config_help.txt +++ b/config_help.txt @@ -298,8 +298,6 @@ Gui, printing, widget options: -xinput2 ........... Enable XInput2 support [auto] -xkbcommon-x11 ..... Select xkbcommon used in combination with xcb [system/qt/no] - -xkb-config-root ... With -qt-xkbcommon-x11, set default XKB config - root [detect] -xkbcommon-evdev ... Enable X-less xkbcommon in combination with libinput [auto] diff --git a/src/3rdparty/xkbcommon.pri b/src/3rdparty/xkbcommon.pri index af71b232d5..1d953d8372 100644 --- a/src/3rdparty/xkbcommon.pri +++ b/src/3rdparty/xkbcommon.pri @@ -6,7 +6,7 @@ INCLUDEPATH += $$PWD/xkbcommon \ include($$shadowed($$PWD/../gui/qtgui-config.pri)) -DEFINES += DFLT_XKB_CONFIG_ROOT='\\"$$QMAKE_XKB_CONFIG_ROOT\\"' +DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"' # unused, but needs to be set to something ### RMLVO names can be overwritten with environmental variables (see libxkbcommon documentation) DEFINES += DEFAULT_XKB_RULES='\\"evdev\\"' diff --git a/src/corelib/serialization/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp index c5a5aaf39d..8ee9ce0de7 100644 --- a/src/corelib/serialization/qjsonarray.cpp +++ b/src/corelib/serialization/qjsonarray.cpp @@ -318,7 +318,8 @@ QJsonArray QJsonArray::fromVariantList(const QVariantList &list) array.a->tableOffset = currentOffset; if (!array.detach2(sizeof(QJsonPrivate::offset)*values.size())) return QJsonArray(); - memcpy(array.a->table(), values.constData(), values.size()*sizeof(uint)); + memcpy(static_cast(array.a->table()), + static_cast(values.constData()), values.size()*sizeof(uint)); array.a->length = values.size(); array.a->size = currentOffset + sizeof(QJsonPrivate::offset)*values.size(); diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index 5645d812eb..4157fbbd0e 100644 --- a/src/corelib/serialization/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h @@ -651,7 +651,8 @@ public: inline void reserve(int extraCapacity) { if (tos + extraCapacity + 1 > cap) { cap = qMax(tos + extraCapacity + 1, cap << 1 ); - data = reinterpret_cast(realloc(data, cap * sizeof(T))); + void *ptr = realloc(static_cast(data), cap * sizeof(T)); + data = reinterpret_cast(ptr); Q_CHECK_PTR(data); } } diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h deleted file mode 100644 index e6c89e40cd..0000000000 --- a/src/corelib/xml/qxmlstream_p.h +++ /dev/null @@ -1,1966 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module 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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -// This file was generated by qlalr - DO NOT EDIT! -#ifndef QXMLSTREAM_P_H -#define QXMLSTREAM_P_H - -#if defined(ERROR) -# undef ERROR -#endif - -class QXmlStreamReader_Table -{ -public: - enum VariousConstants { - EOF_SYMBOL = 0, - AMPERSAND = 5, - ANY = 41, - ATTLIST = 31, - BANG = 25, - CDATA = 47, - CDATA_START = 28, - COLON = 17, - COMMA = 19, - DASH = 20, - DBLQUOTE = 8, - DIGIT = 27, - DOCTYPE = 29, - DOT = 23, - ELEMENT = 30, - EMPTY = 40, - ENTITIES = 51, - ENTITY = 32, - ENTITY_DONE = 45, - EQ = 14, - ERROR = 43, - FIXED = 39, - HASH = 6, - ID = 48, - IDREF = 49, - IDREFS = 50, - IMPLIED = 38, - LANGLE = 3, - LBRACK = 9, - LETTER = 26, - LPAREN = 11, - NDATA = 36, - NMTOKEN = 52, - NMTOKENS = 53, - NOTATION = 33, - NOTOKEN = 1, - PARSE_ENTITY = 44, - PCDATA = 42, - PERCENT = 15, - PIPE = 13, - PLUS = 21, - PUBLIC = 35, - QUESTIONMARK = 24, - QUOTE = 7, - RANGLE = 4, - RBRACK = 10, - REQUIRED = 37, - RPAREN = 12, - SEMICOLON = 18, - SHIFT_THERE = 56, - SLASH = 16, - SPACE = 2, - STAR = 22, - SYSTEM = 34, - UNRESOLVED_ENTITY = 46, - VERSION = 55, - XML = 54, - - ACCEPT_STATE = 416, - RULE_COUNT = 270, - STATE_COUNT = 427, - TERMINAL_COUNT = 57, - NON_TERMINAL_COUNT = 84, - - GOTO_INDEX_OFFSET = 427, - GOTO_INFO_OFFSET = 1017, - GOTO_CHECK_OFFSET = 1017 - }; - - static const char *const spell []; - static const short lhs []; - static const short rhs []; - static const short goto_default []; - static const short action_default []; - static const short action_index []; - static const short action_info []; - static const short action_check []; - - static inline int nt_action (int state, int nt) - { - const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; - if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) - return goto_default [nt]; - - return action_info [GOTO_INFO_OFFSET + yyn]; - } - - static inline int t_action (int state, int token) - { - const int yyn = action_index [state] + token; - - if (yyn < 0 || action_check [yyn] != token) - return - action_default [state]; - - return action_info [yyn]; - } -}; - - -const char *const QXmlStreamReader_Table::spell [] = { - "end of file", 0, " ", "<", ">", "&", "#", "\'", "\"", "[", - "]", "(", ")", "|", "=", "%", "/", ":", ";", ",", - "-", "+", "*", ".", "?", "!", "[a-zA-Z]", "[0-9]", "[CDATA[", "DOCTYPE", - "ELEMENT", "ATTLIST", "ENTITY", "NOTATION", "SYSTEM", "PUBLIC", "NDATA", "REQUIRED", "IMPLIED", "FIXED", - "EMPTY", "ANY", "PCDATA", 0, 0, 0, 0, "CDATA", "ID", "IDREF", - "IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", " class QXmlStreamSimpleStack { - T *data; - int tos, cap; -public: - inline QXmlStreamSimpleStack():data(0), tos(-1), cap(0){} - inline ~QXmlStreamSimpleStack(){ if (data) free(data); } - - inline void reserve(int extraCapacity) { - if (tos + extraCapacity + 1 > cap) { - cap = qMax(tos + extraCapacity + 1, cap << 1 ); - void *ptr = realloc(static_cast(data), cap * sizeof(T)); - data = reinterpret_cast(ptr); - Q_CHECK_PTR(data); - } - } - - inline T &push() { reserve(1); return data[++tos]; } - inline T &rawPush() { return data[++tos]; } - inline const T &top() const { return data[tos]; } - inline T &top() { return data[tos]; } - inline T &pop() { return data[tos--]; } - inline T &operator[](int index) { return data[index]; } - inline const T &at(int index) const { return data[index]; } - inline int size() const { return tos + 1; } - inline void resize(int s) { tos = s - 1; } - inline bool isEmpty() const { return tos < 0; } - inline void clear() { tos = -1; } -}; - - -class QXmlStream -{ - Q_DECLARE_TR_FUNCTIONS(QXmlStream) -}; - -class QXmlStreamPrivateTagStack { -public: - struct NamespaceDeclaration - { - QStringRef prefix; - QStringRef namespaceUri; - }; - - struct Tag - { - QStringRef name; - QStringRef qualifiedName; - NamespaceDeclaration namespaceDeclaration; - int tagStackStringStorageSize; - int namespaceDeclarationsSize; - }; - - - QXmlStreamPrivateTagStack(); - QXmlStreamSimpleStack namespaceDeclarations; - QString tagStackStringStorage; - int tagStackStringStorageSize; - int initialTagStackStringStorageSize; - bool tagsDone; - - inline QStringRef addToStringStorage(const QStringRef &s) { - int pos = tagStackStringStorageSize; - int sz = s.size(); - if (pos != tagStackStringStorage.size()) - tagStackStringStorage.resize(pos); - tagStackStringStorage.insert(pos, s.unicode(), sz); - tagStackStringStorageSize += sz; - return QStringRef(&tagStackStringStorage, pos, sz); - } - inline QStringRef addToStringStorage(const QString &s) { - int pos = tagStackStringStorageSize; - int sz = s.size(); - if (pos != tagStackStringStorage.size()) - tagStackStringStorage.resize(pos); - tagStackStringStorage.insert(pos, s.unicode(), sz); - tagStackStringStorageSize += sz; - return QStringRef(&tagStackStringStorage, pos, sz); - } - - QXmlStreamSimpleStack tagStack; - - - inline Tag &tagStack_pop() { - Tag& tag = tagStack.pop(); - tagStackStringStorageSize = tag.tagStackStringStorageSize; - namespaceDeclarations.resize(tag.namespaceDeclarationsSize); - tagsDone = tagStack.isEmpty(); - return tag; - } - inline Tag &tagStack_push() { - Tag &tag = tagStack.push(); - tag.tagStackStringStorageSize = tagStackStringStorageSize; - tag.namespaceDeclarationsSize = namespaceDeclarations.size(); - return tag; - } -}; - - -class QXmlStreamEntityResolver; -#ifndef QT_NO_XMLSTREAMREADER -class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{ - QXmlStreamReader *q_ptr; - Q_DECLARE_PUBLIC(QXmlStreamReader) -public: - QXmlStreamReaderPrivate(QXmlStreamReader *q); - ~QXmlStreamReaderPrivate(); - void init(); - - QByteArray rawReadBuffer; - QByteArray dataBuffer; - uchar firstByte; - qint64 nbytesread; - QString readBuffer; - int readBufferPos; - QXmlStreamSimpleStack putStack; - struct Entity { - Entity(const QString& str = QString()) - :value(str), external(false), unparsed(false), literal(false), - hasBeenParsed(false), isCurrentlyReferenced(false){} - static inline Entity createLiteral(const QString &entity) - { Entity result(entity); result.literal = result.hasBeenParsed = true; return result; } - QString value; - uint external : 1; - uint unparsed : 1; - uint literal : 1; - uint hasBeenParsed : 1; - uint isCurrentlyReferenced : 1; - }; - QHash entityHash; - QHash parameterEntityHash; - QXmlStreamSimpleStackentityReferenceStack; - inline bool referenceEntity(Entity &entity) { - if (entity.isCurrentlyReferenced) { - raiseWellFormedError(QXmlStream::tr("Recursive entity detected.")); - return false; - } - entity.isCurrentlyReferenced = true; - entityReferenceStack.push() = &entity; - injectToken(ENTITY_DONE); - return true; - } - - - QIODevice *device; - bool deleteDevice; -#ifndef QT_NO_TEXTCODEC - QTextCodec *codec; - QTextDecoder *decoder; -#endif - bool atEnd; - - /*! - \sa setType() - */ - QXmlStreamReader::TokenType type; - QXmlStreamReader::Error error; - QString errorString; - QString unresolvedEntity; - - qint64 lineNumber, lastLineStart, characterOffset; - - - void write(const QString &); - void write(const char *); - - - QXmlStreamAttributes attributes; - QStringRef namespaceForPrefix(const QStringRef &prefix); - void resolveTag(); - void resolvePublicNamespaces(); - void resolveDtd(); - uint resolveCharRef(int symbolIndex); - bool checkStartDocument(); - void startDocument(); - void parseError(); - void checkPublicLiteral(const QStringRef &publicId); - - bool scanDtd; - QStringRef lastAttributeValue; - bool lastAttributeIsCData; - struct DtdAttribute { - QStringRef tagName; - QStringRef attributeQualifiedName; - QStringRef attributePrefix; - QStringRef attributeName; - QStringRef defaultValue; - bool isCDATA; - bool isNamespaceAttribute; - }; - QXmlStreamSimpleStack dtdAttributes; - struct NotationDeclaration { - QStringRef name; - QStringRef publicId; - QStringRef systemId; - }; - QXmlStreamSimpleStack notationDeclarations; - QXmlStreamNotationDeclarations publicNotationDeclarations; - QXmlStreamNamespaceDeclarations publicNamespaceDeclarations; - - struct EntityDeclaration { - QStringRef name; - QStringRef notationName; - QStringRef publicId; - QStringRef systemId; - QStringRef value; - bool parameter; - bool external; - inline void clear() { - name.clear(); - notationName.clear(); - publicId.clear(); - systemId.clear(); - value.clear(); - parameter = external = false; - } - }; - QXmlStreamSimpleStack entityDeclarations; - QXmlStreamEntityDeclarations publicEntityDeclarations; - - QStringRef text; - - QStringRef prefix, namespaceUri, qualifiedName, name; - QStringRef processingInstructionTarget, processingInstructionData; - QStringRef dtdName, dtdPublicId, dtdSystemId; - QStringRef documentVersion, documentEncoding; - uint isEmptyElement : 1; - uint isWhitespace : 1; - uint isCDATA : 1; - uint standalone : 1; - uint hasCheckedStartDocument : 1; - uint normalizeLiterals : 1; - uint hasSeenTag : 1; - uint inParseEntity : 1; - uint referenceToUnparsedEntityDetected : 1; - uint referenceToParameterEntityDetected : 1; - uint hasExternalDtdSubset : 1; - uint lockEncoding : 1; - uint namespaceProcessing : 1; - - int resumeReduction; - void resume(int rule); - - inline bool entitiesMustBeDeclared() const { - return (!inParseEntity - && (standalone - || (!referenceToUnparsedEntityDetected - && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25 - && !hasExternalDtdSubset))); - } - - // qlalr parser - int tos; - int stack_size; - struct Value { - int pos; - int len; - int prefix; - ushort c; - }; - - Value *sym_stack; - int *state_stack; - inline void reallocateStack(); - inline Value &sym(int index) const - { return sym_stack[tos + index - 1]; } - QString textBuffer; - inline void clearTextBuffer() { - if (!scanDtd) { - textBuffer.resize(0); - textBuffer.reserve(256); - } - } - struct Attribute { - Value key; - Value value; - }; - QXmlStreamSimpleStack attributeStack; - - inline QStringRef symString(int index) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); - } - inline QStringRef symName(int index) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos, symbol.len); - } - inline QStringRef symString(int index, int offset) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset); - } - inline QStringRef symPrefix(int index) { - const Value &symbol = sym(index); - if (symbol.prefix) - return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); - return QStringRef(); - } - inline QStringRef symString(const Value &symbol) { - return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); - } - inline QStringRef symName(const Value &symbol) { - return QStringRef(&textBuffer, symbol.pos, symbol.len); - } - inline QStringRef symPrefix(const Value &symbol) { - if (symbol.prefix) - return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); - return QStringRef(); - } - - inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; } - - - short token; - uint token_char; - - uint filterCarriageReturn(); - inline uint getChar(); - inline uint peekChar(); - inline void putChar(uint c) { putStack.push() = c; } - inline void putChar(QChar c) { putStack.push() = c.unicode(); } - void putString(const QString &s, int from = 0); - void putStringLiteral(const QString &s); - void putReplacement(const QString &s); - void putReplacementInAttributeValue(const QString &s); - uint getChar_helper(); - - bool scanUntil(const char *str, short tokenToInject = -1); - bool scanString(const char *str, short tokenToInject, bool requireSpace = true); - inline void injectToken(ushort tokenToInject) { - putChar(int(tokenToInject) << 16); - } - - QString resolveUndeclaredEntity(const QString &name); - void parseEntity(const QString &value); - QXmlStreamReaderPrivate *entityParser; - - bool scanAfterLangleBang(); - bool scanPublicOrSystem(); - bool scanNData(); - bool scanAfterDefaultDecl(); - bool scanAttType(); - - - // scan optimization functions. Not strictly necessary but LALR is - // not very well suited for scanning fast - int fastScanLiteralContent(); - int fastScanSpace(); - int fastScanContentCharList(); - int fastScanName(int *prefix = 0); - inline int fastScanNMTOKEN(); - - - bool parse(); - inline void consumeRule(int); - - void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); - void raiseWellFormedError(const QString &message); - - QXmlStreamEntityResolver *entityResolver; - -private: - /*! \internal - Never assign to variable type directly. Instead use this function. - - This prevents errors from being ignored. - */ - inline void setType(const QXmlStreamReader::TokenType t) - { - if(type != QXmlStreamReader::Invalid) - type = t; - } -}; - -bool QXmlStreamReaderPrivate::parse() -{ - // cleanup currently reported token - - switch (type) { - case QXmlStreamReader::StartElement: - name.clear(); - prefix.clear(); - qualifiedName.clear(); - namespaceUri.clear(); - publicNamespaceDeclarations.clear(); - attributes.clear(); - if (isEmptyElement) { - setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); - namespaceUri = tag.namespaceDeclaration.namespaceUri; - name = tag.name; - qualifiedName = tag.qualifiedName; - isEmptyElement = false; - return true; - } - clearTextBuffer(); - break; - case QXmlStreamReader::EndElement: - name.clear(); - prefix.clear(); - qualifiedName.clear(); - namespaceUri.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::DTD: - publicNotationDeclarations.clear(); - publicEntityDeclarations.clear(); - dtdName.clear(); - dtdPublicId.clear(); - dtdSystemId.clear(); - Q_FALLTHROUGH(); - case QXmlStreamReader::Comment: - case QXmlStreamReader::Characters: - isCDATA = false; - isWhitespace = true; - text.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::EntityReference: - text.clear(); - name.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::ProcessingInstruction: - processingInstructionTarget.clear(); - processingInstructionData.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::NoToken: - case QXmlStreamReader::Invalid: - break; - case QXmlStreamReader::StartDocument: - lockEncoding = true; - documentVersion.clear(); - documentEncoding.clear(); -#ifndef QT_NO_TEXTCODEC - if (decoder && decoder->hasFailure()) { - raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); - readBuffer.clear(); - return false; - } -#endif - Q_FALLTHROUGH(); - default: - clearTextBuffer(); - ; - } - - setType(QXmlStreamReader::NoToken); - - - // the main parse loop - int act, r; - - if (resumeReduction) { - act = state_stack[tos-1]; - r = resumeReduction; - resumeReduction = 0; - goto ResumeReduction; - } - - act = state_stack[tos]; - - forever { - if (token == -1 && - TERMINAL_COUNT != action_index[act]) { - uint cu = getChar(); - token = NOTOKEN; - token_char = cu == ~0U ? cu : ushort(cu); - if ((cu != ~0U) && (cu & 0xff0000)) { - token = cu >> 16; - } else switch (token_char) { - case 0xfffe: - case 0xffff: - token = ERROR; - break; - case '\r': - token = SPACE; - if (cu == '\r') { - if ((token_char = filterCarriageReturn())) { - ++lineNumber; - lastLineStart = characterOffset + readBufferPos; - break; - } - } else { - break; - } - Q_FALLTHROUGH(); - case ~0U: { - token = EOF_SYMBOL; - if (!tagsDone && !inParseEntity) { - int a = t_action(act, token); - if (a < 0) { - raiseError(QXmlStreamReader::PrematureEndOfDocumentError); - return false; - } - } - - } break; - case '\n': - ++lineNumber; - lastLineStart = characterOffset + readBufferPos; - Q_FALLTHROUGH(); - case ' ': - case '\t': - token = SPACE; - break; - case '&': - token = AMPERSAND; - break; - case '#': - token = HASH; - break; - case '\'': - token = QUOTE; - break; - case '\"': - token = DBLQUOTE; - break; - case '<': - token = LANGLE; - break; - case '>': - token = RANGLE; - break; - case '[': - token = LBRACK; - break; - case ']': - token = RBRACK; - break; - case '(': - token = LPAREN; - break; - case ')': - token = RPAREN; - break; - case '|': - token = PIPE; - break; - case '=': - token = EQ; - break; - case '%': - token = PERCENT; - break; - case '/': - token = SLASH; - break; - case ':': - token = COLON; - break; - case ';': - token = SEMICOLON; - break; - case ',': - token = COMMA; - break; - case '-': - token = DASH; - break; - case '+': - token = PLUS; - break; - case '*': - token = STAR; - break; - case '.': - token = DOT; - break; - case '?': - token = QUESTIONMARK; - break; - case '!': - token = BANG; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token = DIGIT; - break; - default: - if (cu < 0x20) - token = NOTOKEN; - else - token = LETTER; - break; - } - } - - act = t_action (act, token); - if (act == ACCEPT_STATE) { - // reset the parser in case someone resumes (process instructions can follow a valid document) - tos = 0; - state_stack[tos++] = 0; - state_stack[tos] = 0; - return true; - } else if (act > 0) { - if (++tos == stack_size-1) - reallocateStack(); - - Value &val = sym_stack[tos]; - val.c = token_char; - val.pos = textBuffer.size(); - val.prefix = 0; - val.len = 1; - if (token_char) - textBuffer += QChar(token_char); - - state_stack[tos] = act; - token = -1; - - - } else if (act < 0) { - r = - act - 1; - -#if defined (QLALR_DEBUG) - int ridx = rule_index[r]; - printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]); - ++ridx; - for (int i = ridx; i < ridx + rhs[r]; ++i) { - int symbol = rule_info[i]; - if (const char *name = spell[symbol]) - printf (" %s", name); - else - printf (" #%d", symbol); - } - printf ("\n"); -#endif - - tos -= rhs[r]; - act = state_stack[tos++]; - ResumeReduction: - switch (r) { - - case 0: - setType(QXmlStreamReader::EndDocument); - break; - - case 1: - if (type != QXmlStreamReader::Invalid) { - if (hasSeenTag || inParseEntity) { - setType(QXmlStreamReader::EndDocument); - } else { - raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected.")); - // reset the parser - tos = 0; - state_stack[tos++] = 0; - state_stack[tos] = 0; - return false; - } - } - break; - - case 10: - entityReferenceStack.pop()->isCurrentlyReferenced = false; - clearSym(); - break; - - case 11: - if (!scanString(spell[VERSION], VERSION, false) && atEnd) { - resume(11); - return false; - } - break; - - case 12: - setType(QXmlStreamReader::StartDocument); - documentVersion = symString(6); - startDocument(); - break; - - case 13: - hasExternalDtdSubset = true; - dtdSystemId = symString(2); - break; - - case 14: - checkPublicLiteral(symString(2)); - dtdPublicId = symString(2); - dtdSystemId = symString(4); - hasExternalDtdSubset = true; - break; - - case 16: - if (!scanPublicOrSystem() && atEnd) { - resume(16); - return false; - } - dtdName = symString(3); - break; - - case 17: - case 18: - dtdName = symString(3); - Q_FALLTHROUGH(); - - case 19: - case 20: - setType(QXmlStreamReader::DTD); - text = &textBuffer; - break; - - case 21: - scanDtd = true; - break; - - case 22: - scanDtd = false; - break; - - case 37: - if (!scanString(spell[EMPTY], EMPTY, false) - && !scanString(spell[ANY], ANY, false) - && atEnd) { - resume(37); - return false; - } - break; - - case 43: - if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { - resume(43); - return false; - } - break; - - case 68: { - lastAttributeIsCData = true; - } break; - - case 78: - if (!scanAfterDefaultDecl() && atEnd) { - resume(78); - return false; - } - break; - - case 83: - sym(1) = sym(2); - lastAttributeValue.clear(); - lastAttributeIsCData = false; - if (!scanAttType() && atEnd) { - resume(83); - return false; - } - break; - - case 84: { - DtdAttribute &dtdAttribute = dtdAttributes.push(); - dtdAttribute.tagName.clear(); - dtdAttribute.isCDATA = lastAttributeIsCData; - dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1)); - dtdAttribute.attributeName = addToStringStorage(symString(1)); - dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1)); - dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns") - || (dtdAttribute.attributePrefix.isEmpty() - && dtdAttribute.attributeName == QLatin1String("xmlns"))); - if (lastAttributeValue.isNull()) { - dtdAttribute.defaultValue.clear(); - } else { - if (dtdAttribute.isCDATA) - dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue); - else - dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified()); - - } - } break; - - case 88: { - if (referenceToUnparsedEntityDetected && !standalone) - break; - int n = dtdAttributes.size(); - QStringRef tagName = addToStringStorage(symName(3)); - while (n--) { - DtdAttribute &dtdAttribute = dtdAttributes[n]; - if (!dtdAttribute.tagName.isNull()) - break; - dtdAttribute.tagName = tagName; - for (int i = 0; i < n; ++i) { - if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName) - && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) { - dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it - break; - } - } - } - } break; - - case 89: { - if (!scanPublicOrSystem() && atEnd) { - resume(89); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.push(); - entityDeclaration.clear(); - entityDeclaration.name = symString(3); - } break; - - case 90: { - if (!scanPublicOrSystem() && atEnd) { - resume(90); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.push(); - entityDeclaration.clear(); - entityDeclaration.name = symString(5); - entityDeclaration.parameter = true; - } break; - - case 91: { - if (!scanNData() && atEnd) { - resume(91); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - entityDeclaration.systemId = symString(3); - entityDeclaration.external = true; - } break; - - case 92: { - if (!scanNData() && atEnd) { - resume(92); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - checkPublicLiteral((entityDeclaration.publicId = symString(3))); - entityDeclaration.systemId = symString(5); - entityDeclaration.external = true; - } break; - - case 93: { - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - entityDeclaration.notationName = symString(3); - if (entityDeclaration.parameter) - raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); - } - Q_FALLTHROUGH(); - - case 94: - case 95: { - if (referenceToUnparsedEntityDetected && !standalone) { - entityDeclarations.pop(); - break; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - if (!entityDeclaration.external) - entityDeclaration.value = symString(2); - QString entityName = entityDeclaration.name.toString(); - QHash &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash; - if (!hash.contains(entityName)) { - Entity entity(entityDeclaration.value.toString()); - entity.unparsed = (!entityDeclaration.notationName.isNull()); - entity.external = entityDeclaration.external; - hash.insert(entityName, entity); - } - } break; - - case 96: { - setType(QXmlStreamReader::ProcessingInstruction); - int pos = sym(4).pos + sym(4).len; - processingInstructionTarget = symString(3); - if (scanUntil("?>")) { - processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); - const QString piTarget(processingInstructionTarget.toString()); - if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) { - raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document.")); - } - else if(!QXmlUtils::isNCName(piTarget)) - raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget)); - } else if (type != QXmlStreamReader::Invalid){ - resume(96); - return false; - } - } break; - - case 97: - setType(QXmlStreamReader::ProcessingInstruction); - processingInstructionTarget = symString(3); - if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive)) - raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); - break; - - case 98: - if (!scanAfterLangleBang() && atEnd) { - resume(98); - return false; - } - break; - - case 99: - if (!scanUntil("--")) { - resume(99); - return false; - } - break; - - case 100: { - setType(QXmlStreamReader::Comment); - int pos = sym(1).pos + 4; - text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); - } break; - - case 101: { - setType(QXmlStreamReader::Characters); - isCDATA = true; - isWhitespace = false; - int pos = sym(2).pos; - if (scanUntil("]]>", -1)) { - text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); - } else { - resume(101); - return false; - } - } break; - - case 102: { - if (!scanPublicOrSystem() && atEnd) { - resume(102); - return false; - } - NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); - notationDeclaration.name = symString(3); - } break; - - case 103: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - notationDeclaration.systemId = symString(3); - notationDeclaration.publicId.clear(); - } break; - - case 104: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - notationDeclaration.systemId.clear(); - checkPublicLiteral((notationDeclaration.publicId = symString(3))); - } break; - - case 105: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - checkPublicLiteral((notationDeclaration.publicId = symString(3))); - notationDeclaration.systemId = symString(5); - } break; - - case 129: - isWhitespace = false; - Q_FALLTHROUGH(); - - case 130: - sym(1).len += fastScanContentCharList(); - if (atEnd && !inParseEntity) { - resume(130); - return false; - } - break; - - case 139: - if (!textBuffer.isEmpty()) { - setType(QXmlStreamReader::Characters); - text = &textBuffer; - } - break; - - case 140: - case 141: - clearSym(); - break; - - case 142: - case 143: - sym(1) = sym(2); - break; - - case 144: - case 145: - case 146: - case 147: - sym(1).len += sym(2).len; - break; - - case 173: - if (normalizeLiterals) - textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); - break; - - case 174: - sym(1).len += fastScanLiteralContent(); - if (atEnd) { - resume(174); - return false; - } - break; - - case 175: { - if (!QXmlUtils::isPublicID(symString(1).toString())) { - raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString())); - resume(175); - return false; - } - } break; - - case 176: - case 177: - clearSym(); - break; - - case 178: - case 179: - sym(1) = sym(2); - break; - - case 180: - case 181: - case 182: - case 183: - sym(1).len += sym(2).len; - break; - - case 213: - case 214: - clearSym(); - break; - - case 215: - case 216: - sym(1) = sym(2); - lastAttributeValue = symString(1); - break; - - case 217: - case 218: - case 219: - case 220: - sym(1).len += sym(2).len; - break; - - case 229: { - QStringRef prefix = symPrefix(1); - if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { - NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); - namespaceDeclaration.prefix.clear(); - - const QStringRef ns(symString(5)); - if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || - ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) - raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); - else - namespaceDeclaration.namespaceUri = addToStringStorage(ns); - } else { - Attribute &attribute = attributeStack.push(); - attribute.key = sym(1); - attribute.value = sym(5); - - QStringRef attributeQualifiedName = symName(1); - bool normalize = false; - for (int a = 0; a < dtdAttributes.size(); ++a) { - DtdAttribute &dtdAttribute = dtdAttributes[a]; - if (!dtdAttribute.isCDATA - && dtdAttribute.tagName == qualifiedName - && dtdAttribute.attributeQualifiedName == attributeQualifiedName - ) { - normalize = true; - break; - } - } - if (normalize) { - // normalize attribute value (simplify and trim) - int pos = textBuffer.size(); - int n = 0; - bool wasSpace = true; - for (int i = 0; i < attribute.value.len; ++i) { - QChar c = textBuffer.at(attribute.value.pos + i); - if (c.unicode() == ' ') { - if (wasSpace) - continue; - wasSpace = true; - } else { - wasSpace = false; - } - textBuffer += textBuffer.at(attribute.value.pos + i); - ++n; - } - if (wasSpace) - while (n && textBuffer.at(pos + n - 1).unicode() == ' ') - --n; - attribute.value.pos = pos; - attribute.value.len = n; - } - if (prefix == QLatin1String("xmlns") && namespaceProcessing) { - NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); - QStringRef namespacePrefix = symString(attribute.key); - QStringRef namespaceUri = symString(attribute.value); - attributeStack.pop(); - if (((namespacePrefix == QLatin1String("xml")) - ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))) - || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") - || namespaceUri.isEmpty() - || namespacePrefix == QLatin1String("xmlns")) - raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); - - namespaceDeclaration.prefix = addToStringStorage(namespacePrefix); - namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); - } - } - } break; - - case 235: { - normalizeLiterals = true; - Tag &tag = tagStack_push(); - prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2)); - name = tag.name = addToStringStorage(symString(2)); - qualifiedName = tag.qualifiedName = addToStringStorage(symName(2)); - if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name)) - raiseWellFormedError(QXmlStream::tr("Invalid XML name.")); - } break; - - case 236: - isEmptyElement = true; - Q_FALLTHROUGH(); - - case 237: - setType(QXmlStreamReader::StartElement); - resolveTag(); - if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) - raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); - hasSeenTag = true; - break; - - case 238: { - setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); - - namespaceUri = tag.namespaceDeclaration.namespaceUri; - name = tag.name; - qualifiedName = tag.qualifiedName; - if (qualifiedName != symName(3)) - raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); - } break; - - case 239: - if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); - break; - } - setType(QXmlStreamReader::EntityReference); - name = &unresolvedEntity; - break; - - case 240: { - sym(1).len += sym(2).len + 1; - QString reference = symString(2).toString(); - if (entityHash.contains(reference)) { - Entity &entity = entityHash[reference]; - if (entity.unparsed) { - raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference)); - } else { - if (!entity.hasBeenParsed) { - parseEntity(entity.value); - entity.hasBeenParsed = true; - } - if (entity.literal) - putStringLiteral(entity.value); - else if (referenceEntity(entity)) - putReplacement(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - } - break; - } - - if (entityResolver) { - QString replacementText = resolveUndeclaredEntity(reference); - if (!replacementText.isNull()) { - putReplacement(replacementText); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - } - - injectToken(UNRESOLVED_ENTITY); - unresolvedEntity = symString(2).toString(); - textBuffer.chop(2 + sym(2).len); - clearSym(); - - } break; - - case 241: { - sym(1).len += sym(2).len + 1; - QString reference = symString(2).toString(); - if (parameterEntityHash.contains(reference)) { - referenceToParameterEntityDetected = true; - Entity &entity = parameterEntityHash[reference]; - if (entity.unparsed || entity.external) { - referenceToUnparsedEntityDetected = true; - } else { - if (referenceEntity(entity)) - putString(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - } - } else if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString())); - } - } break; - - case 242: - sym(1).len += sym(2).len + 1; - break; - - case 243: { - sym(1).len += sym(2).len + 1; - QString reference = symString(2).toString(); - if (entityHash.contains(reference)) { - Entity &entity = entityHash[reference]; - if (entity.unparsed || entity.value.isNull()) { - raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference)); - break; - } - if (!entity.hasBeenParsed) { - parseEntity(entity.value); - entity.hasBeenParsed = true; - } - if (entity.literal) - putStringLiteral(entity.value); - else if (referenceEntity(entity)) - putReplacementInAttributeValue(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - - if (entityResolver) { - QString replacementText = resolveUndeclaredEntity(reference); - if (!replacementText.isNull()) { - putReplacement(replacementText); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - } - if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference)); - } - } break; - - case 244: { - if (uint s = resolveCharRef(3)) { - if (s >= 0xffff) - putStringLiteral(QString::fromUcs4(&s, 1)); - else - putChar((LETTER << 16) | s); - - textBuffer.chop(3 + sym(3).len); - clearSym(); - } else { - raiseWellFormedError(QXmlStream::tr("Invalid character reference.")); - } - } break; - - case 247: - case 248: - sym(1).len += sym(2).len; - break; - - case 259: - sym(1).len += fastScanSpace(); - if (atEnd) { - resume(259); - return false; - } - break; - - case 262: { - sym(1).len += fastScanName(&sym(1).prefix); - if (atEnd) { - resume(262); - return false; - } - } break; - - case 263: - sym(1).len += fastScanName(); - if (atEnd) { - resume(263); - return false; - } - break; - - case 264: - case 265: - case 266: - case 267: - case 268: - sym(1).len += fastScanNMTOKEN(); - if (atEnd) { - resume(268); - return false; - } - - break; - - default: - ; - } // switch - act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT); - if (type != QXmlStreamReader::NoToken) - return true; - } else { - parseError(); - break; - } - } - return false; -} -#endif //QT_NO_XMLSTREAMREADER.xml - - -#endif // QXMLSTREAM_P_H - diff --git a/src/gui/configure.json b/src/gui/configure.json index 27e913877f..220662ea8e 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -46,7 +46,6 @@ "xcb-xlib": "boolean", "xinput2": "boolean", "xkb": "boolean", - "xkb-config-root": "string", "xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] }, "xkbcommon-evdev": "boolean", "xkbcommon-x11": { "type": "enum", "name": "xkbcommon", "values": [ "no", "qt", "system" ] } @@ -624,8 +623,7 @@ }, "testTypeAliases": { - "files": [ "directX" ], - "getPkgConfigVariable": [ "xkbConfigRoot" ] + "files": [ "directX" ] }, "tests": { @@ -888,13 +886,6 @@ "value": "/usr", "log": "value" }, - "xkbconfigroot": { - "label": "XKB config root", - "type": "xkbConfigRoot", - "pkg-config-args": "xkeyboard-config", - "pkg-config-variable": "xkb_base", - "log": "value" - }, "xlib": { "label": "XLib", "type": "compile", @@ -1355,12 +1346,6 @@ "condition": "libs.xkbcommon_x11", "output": [ "privateFeature" ] }, - "xkb-config-root": { - "label": "XKB config root", - "emitIf": "features.xcb", - "condition": "features.xcb && !features.xkbcommon-system && tests.xkbconfigroot", - "output": [ { "type": "varAssign", "name": "QMAKE_XKB_CONFIG_ROOT", "value": "tests.xkbconfigroot.value"} ] - }, "xlib": { "label": "XLib", "autoDetect": "!config.darwin || features.xcb", @@ -1579,12 +1564,6 @@ ], "report": [ - { - "type": "warning", - "condition": "features.xcb && !features.xkbcommon-system && !features.xkb-config-root", - "message": "Could not find XKB config root, use -xkb-config-root to set a path to -XKB configuration data. This is required for keyboard input support." - }, { "type": "note", "condition": "features.xcb && config.darwin", diff --git a/src/gui/configure.pri b/src/gui/configure.pri index aaffa835dc..fcd2d1f73e 100644 --- a/src/gui/configure.pri +++ b/src/gui/configure.pri @@ -42,21 +42,6 @@ defineTest(qtConfTest_directX) { return(false) } -defineTest(qtConfTest_xkbConfigRoot) { - qtConfTest_getPkgConfigVariable($${1}): return(true) - - for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) { - exists($$dir) { - $${1}.value = $$dir - export($${1}.value) - $${1}.cache += value - export($${1}.cache) - return(true) - } - } - return(false) -} - defineTest(qtConfTest_qpaDefaultPlatform) { name = !isEmpty(config.input.qpa_default_platform): name = $$config.input.qpa_default_platform diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 20b5fe039a..d00d69586a 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -39,18 +39,17 @@ #include "qxcbkeyboard.h" #include "qxcbwindow.h" #include "qxcbscreen.h" +#include "qxcbxkbcommon.h" #include #include #include #include -#include -#include -#include +#include + #include -#include #include #if QT_CONFIG(xinput2) @@ -59,12 +58,6 @@ #undef KeyRelease #endif -#if QT_CONFIG(xcb_xlib) -#include -#undef KeyPress -#undef KeyRelease -#endif - #ifndef XK_ISO_Left_Tab #define XK_ISO_Left_Tab 0xFE20 #endif @@ -706,76 +699,6 @@ Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const return ret; } -void QXcbKeyboard::readXKBConfig() -{ - clearXKBConfig(); - - xcb_connection_t *c = xcb_connection(); - xcb_window_t rootWindow = connection()->rootWindow(); - - auto config_reply = Q_XCB_REPLY(xcb_get_property, c, 0, rootWindow, - atom(QXcbAtom::_XKB_RULES_NAMES), XCB_ATOM_STRING, 0, 1024); - if (!config_reply) { - qWarning("Qt: Couldn't interpret the _XKB_RULES_NAMES property"); - return; - } - char *xkb_config = (char *)xcb_get_property_value(config_reply.get()); - int length = xcb_get_property_value_length(config_reply.get()); - - // 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; - // The result from xcb_get_property_value() is not necessarily \0-terminated, - // we need to make sure that too many or missing '\0' symbols are handled safely. - do { - uint len = qstrnlen(p, length); - names[i++] = p; - p += len + 1; - length -= len + 1; - } while (p < end || i < 5); - - xkb_names.rules = qstrdup(names[0]); - xkb_names.model = qstrdup(names[1]); - xkb_names.layout = qstrdup(names[2]); - xkb_names.variant = qstrdup(names[3]); - xkb_names.options = qstrdup(names[4]); -} - -void QXcbKeyboard::clearXKBConfig() -{ - if (xkb_names.rules) - delete[] xkb_names.rules; - if (xkb_names.model) - delete[] xkb_names.model; - if (xkb_names.layout) - delete[] xkb_names.layout; - if (xkb_names.variant) - delete[] xkb_names.variant; - if (xkb_names.options) - delete[] xkb_names.options; - memset(&xkb_names, 0, sizeof(xkb_names)); -} - -void QXcbKeyboard::printKeymapError(const char *error) const -{ - qWarning() << error; - if (xkb_context) { - qWarning("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/ ."); -} - -#if QT_CONFIG(xcb_xlib) /* Look at a pair of unshifted and shifted key symbols. * If the 'unshifted' symbol is uppercase and there is no shifted symbol, * return the matching lowercase symbol; otherwise return 0. @@ -787,18 +710,15 @@ static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifte if (shifted != XKB_KEY_NoSymbol) // Has a shifted symbol return 0; - KeySym xlower; - KeySym xupper; - /* libxkbcommon >= 0.8.0 will have public API functions providing - * functionality equivalent to XConvertCase(), use these once the - * minimal libxkbcommon version is high enough. After that the - * xcb-xlib dependency can be removed */ - XConvertCase(static_cast(unshifted), &xlower, &xupper); + xcb_keysym_t xlower; + xcb_keysym_t xupper; + xkbcommon_XConvertCase(unshifted, &xlower, &xupper); - if (xlower != xupper // Check if symbol is cased - && unshifted == static_cast(xupper)) { // Unshifted must be upper case - return static_cast(xlower); + if (xlower != xupper // Check if symbol is cased + && unshifted == xupper) { // Unshifted must be upper case + return xlower; } + return 0; } @@ -1060,92 +980,55 @@ struct xkb_keymap *QXcbKeyboard::keymapFromCore() keymap += "};\n"; // xkb_keymap - return xkb_keymap_new_from_buffer(xkb_context, + return xkb_keymap_new_from_buffer(m_xkbContext.get(), keymap.constData(), keymap.size(), XKB_KEYMAP_FORMAT_TEXT_V1, - static_cast(0)); + XKB_KEYMAP_COMPILE_NO_FLAGS); } -#endif void QXcbKeyboard::updateKeymap() { m_config = true; - m_keymap_is_core = false; - // set xkb context object - if (!xkb_context) { - if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) { - xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES); - const QList xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':'); - for (const 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) { - printKeymapError("Qt: Failed to create XKB context!"); + + if (!m_xkbContext) { + m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES)); + if (!m_xkbContext) { + qCWarning(lcQpaKeyboard, "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); + xkb_log_level logLevel = lcQpaKeyboard().isDebugEnabled() ? + XKB_LOG_LEVEL_DEBUG : XKB_LOG_LEVEL_CRITICAL; + xkb_context_set_log_level(m_xkbContext.get(), logLevel); } - // update xkb keymap object - xkb_keymap_unref(xkb_keymap); - xkb_keymap = 0; - struct xkb_state *new_state = 0; #if QT_CONFIG(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); - } + m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), xcb_connection(), + core_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS)); + if (m_xkbKeymap) + m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), xcb_connection(), core_device_id)); + } else { +#endif + m_xkbKeymap.reset(keymapFromCore()); + if (m_xkbKeymap) + m_xkbState.reset(xkb_state_new(m_xkbKeymap.get())); +#if QT_CONFIG(xkb) } #endif - if (!xkb_keymap) { - // Read xkb RMLVO (rules, models, layouts, variants and options) names - readXKBConfig(); -#if QT_CONFIG(xcb_xlib) - bool rmlvo_is_incomplete = !xkb_names.rules || !(*xkb_names.rules) - || !xkb_names.model || !(*xkb_names.model) - || !xkb_names.layout || !(*xkb_names.layout); - if (rmlvo_is_incomplete) { - // Try to build xkb map from core mapping information - xkb_keymap = keymapFromCore(); - m_keymap_is_core = xkb_keymap != 0; - } -#endif - if (!xkb_keymap) { - // Compile a keymap from RMLVO - xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, - static_cast (0)); - } - 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 { - printKeymapError("Qt: Failed to compile a keymap!"); - m_config = false; - return; - } - } - if (!new_state) { - qWarning("Qt: Failed to create xkb state!"); + if (!m_xkbKeymap) { + qCWarning(lcQpaKeyboard, "failed to compile a keymap"); m_config = false; return; } - // update xkb state object - xkb_state_unref(xkb_state); - xkb_state = new_state; + if (!m_xkbState) { + qCWarning(lcQpaKeyboard, "failed to create XKB state"); + m_config = false; + return; + } + updateXKBMods(); checkForLatinLayout(); @@ -1156,7 +1039,7 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) { if (m_config && connection()->hasXKB()) { const xkb_state_component newState - = xkb_state_update_mask(xkb_state, + = xkb_state_update_mask(m_xkbState.get(), state->baseMods, state->latchedMods, state->lockedMods, @@ -1201,7 +1084,7 @@ void QXcbKeyboard::updateXKBStateFromState(struct xkb_state *kb_state, quint16 s void QXcbKeyboard::updateXKBStateFromCore(quint16 state) { if (m_config && !connection()->hasXKB()) { - updateXKBStateFromState(xkb_state, state); + updateXKBStateFromState(m_xkbState.get(), state); } } @@ -1211,7 +1094,7 @@ void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo) if (m_config && !connection()->hasXKB()) { xXIModifierInfo *mods = static_cast(modInfo); xXIGroupInfo *group = static_cast(groupInfo); - const xkb_state_component newState = xkb_state_update_mask(xkb_state, + const xkb_state_component newState = xkb_state_update_mask(m_xkbState.get(), mods->base_mods, mods->latched_mods, mods->locked_mods, @@ -1252,14 +1135,14 @@ quint32 QXcbKeyboard::xkbModMask(quint16 state) void QXcbKeyboard::updateXKBMods() { - 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"); + xkb_mods.shift = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_SHIFT); + xkb_mods.lock = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CAPS); + xkb_mods.control = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CTRL); + xkb_mods.mod1 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod1"); + xkb_mods.mod2 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod2"); + xkb_mods.mod3 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod3"); + xkb_mods.mod4 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod4"); + xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5"); } static bool isLatin(xkb_keysym_t sym) @@ -1269,11 +1152,11 @@ static bool isLatin(xkb_keysym_t sym) void QXcbKeyboard::checkForLatinLayout() const { - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(xkb_keymap); + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(m_xkbKeymap.get()); const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; - ScopedXKBState state(xkb_state_new(xkb_keymap)); + ScopedXKBState state(xkb_state_new(m_xkbKeymap.get())); for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { xkb_state_update_mask(state.get(), 0, 0, 0, 0, 0, layout); for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { @@ -1299,16 +1182,16 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const { xkb_layout_index_t layout; xkb_keysym_t sym = XKB_KEY_NoSymbol; - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(xkb_keymap, keycode); - const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(xkb_state, keycode); + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(m_xkbKeymap.get(), keycode); + const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(m_xkbState.get(), keycode); // Look at user layouts in the order in which they are defined in system // settings to find a latin keysym. for (layout = 0; layout < layoutCount; ++layout) { if (layout == currentLayout) continue; const xkb_keysym_t *syms; - xkb_level_index_t level = xkb_state_key_get_level(xkb_state, keycode, layout); - if (xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, layout, level, &syms) != 1) + xkb_level_index_t level = xkb_state_key_get_level(m_xkbState.get(), keycode, layout); + if (xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), keycode, layout, level, &syms) != 1) continue; if (isLatin(syms[0])) { sym = syms[0]; @@ -1319,8 +1202,8 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const if (sym == XKB_KEY_NoSymbol) return sym; - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); // Check for uniqueness, consider the following setup: // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). @@ -1332,7 +1215,7 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const // generate the same shortcut event in this case. const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; - ScopedXKBState state(xkb_state_new(xkb_keymap)); + ScopedXKBState state(xkb_state_new(m_xkbKeymap.get())); for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { xkb_state_update_mask(state.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout); for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { @@ -1347,22 +1230,29 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const return sym; } +static const char *qtKeyName(int qtKey) +{ + int keyEnumIndex = qt_getQtMetaObject()->indexOfEnumerator("Key"); + QMetaEnum keyEnum = qt_getQtMetaObject()->enumerator(keyEnumIndex); + return keyEnum.valueToKey(qtKey); +} + QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const { // turn off the modifier bits which doesn't participate in shortcuts Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier; Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; // create a fresh kb state and test against the relevant modifier combinations - struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + struct xkb_state *kb_state = xkb_state_new(m_xkbKeymap.get()); if (!kb_state) { qWarning("QXcbKeyboard: failed to compile xkb keymap!"); return QList(); } // get kb state from the master xkb_state and update the temporary kb_state - xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LOCKED); - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); - xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); + xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(m_xkbState.get(), XKB_STATE_LAYOUT_LOCKED); + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); + xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_DEPRESSED); xkb_state_update_mask(kb_state, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout); quint32 keycode = event->nativeScanCode(); @@ -1384,14 +1274,14 @@ QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const } QList result; - int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, keycode)); + int baseQtKey = keysymToQtKey(sym, modifiers, kb_state, keycode); if (baseQtKey) result += (baseQtKey + modifiers); - xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); - xkb_mod_index_t altMod = xkb_keymap_mod_get_index(xkb_keymap, "Alt"); - xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(xkb_keymap, "Control"); - xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(xkb_keymap, "Meta"); + xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Shift"); + xkb_mod_index_t altMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Alt"); + xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Control"); + xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Meta"); Q_ASSERT(shiftMod < 32); Q_ASSERT(altMod < 32); @@ -1425,7 +1315,7 @@ QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const continue; Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, keycode)); + qtKey = keysymToQtKey(sym, mods, kb_state, keycode); if (!qtKey || qtKey == baseQtKey) continue; @@ -1446,77 +1336,88 @@ QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const } xkb_state_unref(kb_state); return result; - } +} -int QXcbKeyboard::keysymToQtKey(xcb_keysym_t key) const +int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + struct xkb_state *state, xcb_keycode_t code) const { - int code = 0; - int i = 0; - while (KeyTbl[i]) { - if (key == KeyTbl[i]) { - code = (int)KeyTbl[i+1]; - break; + int qtKey = 0; + + // lookup from direct mapping + if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { + // function keys + qtKey = Qt::Key_F1 + (keysym - XKB_KEY_F1); + } else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) { + // numeric keypad keys + qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0); + } else if (isLatin(keysym)) { + qtKey = xkbcommon_xkb_keysym_to_upper(keysym); + } else { + // check if we have a direct mapping + int i = 0; + while (KeyTbl[i]) { + if (keysym == KeyTbl[i]) { + qtKey = KeyTbl[i + 1]; + break; + } + i += 2; + } + } + + QString text; + bool fromUnicode = qtKey == 0; + if (fromUnicode) { // lookup from unicode + if (modifiers & Qt::ControlModifier) { + // Control modifier changes the text to ASCII control character, therefore we + // can't use this text to map keysym to a qt key. We can use the same keysym + // (it is not affectd by transformation) to obtain untransformed text. For details + // see "Appendix A. Default Symbol Transformations" in the XKB specification. + text = lookupStringNoKeysymTransformations(keysym); + } else { + text = lookupString(state, code); + } + if (!text.isEmpty()) { + if (text.unicode()->isDigit()) { + // Ensures that also non-latin digits are mapped to corresponding qt keys, + // e.g CTRL + ۲ (arabic two), is mapped to CTRL + Qt::Key_2. + qtKey = Qt::Key_0 + text.unicode()->digitValue(); + } else { + qtKey = text.unicode()->toUpper().unicode(); + } } - i += 2; } if (rmod_masks.meta) { // translate Super/Hyper keys to Meta if we're using them as the MetaModifier - if (rmod_masks.meta == rmod_masks.super && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) { - code = Qt::Key_Meta; - } else if (rmod_masks.meta == rmod_masks.hyper && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) { - code = Qt::Key_Meta; + if (rmod_masks.meta == rmod_masks.super && (qtKey == Qt::Key_Super_L + || qtKey == Qt::Key_Super_R)) { + qtKey = Qt::Key_Meta; + } else if (rmod_masks.meta == rmod_masks.hyper && (qtKey == Qt::Key_Hyper_L + || qtKey == Qt::Key_Hyper_R)) { + qtKey = Qt::Key_Meta; } } - return code; -} - -int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) const -{ - int code = 0; -#ifndef QT_NO_TEXTCODEC - QTextCodec *systemCodec = QTextCodec::codecForLocale(); -#endif - // Commentary in X11/keysymdef says that X codes match ASCII, so it - // is safe to use the locale functions to process X codes in ISO8859-1. - // This is mainly for compatibility - applications should not use the - // Qt keycodes between 128 and 255 (extended ACSII codes), but should - // rather use the QKeyEvent::text(). - if (keysym < 128 || (keysym < 256 -#ifndef QT_NO_TEXTCODEC - && systemCodec->mibEnum() == 4 -#endif - )) { - // upper-case key, if known - code = isprint((int)keysym) ? toupper((int)keysym) : 0; - } else if (keysym >= XK_F1 && keysym <= XK_F35) { - // function keys - code = Qt::Key_F1 + ((int)keysym - XK_F1); - } else if (keysym >= XK_KP_Space && keysym <= XK_KP_9) { - if (keysym >= XK_KP_0) { - // numeric keypad keys - code = Qt::Key_0 + ((int)keysym - XK_KP_0); + if (Q_UNLIKELY(lcQpaKeyboard().isDebugEnabled())) { + char keysymName[64]; + xkb_keysym_get_name(keysym, keysymName, sizeof(keysymName)); + QString keysymInHex = QString(QStringLiteral("0x%1")).arg(keysym, 0, 16); + if (qtKeyName(qtKey)) { + qCDebug(lcQpaKeyboard).nospace() << "keysym: " << keysymName << "(" + << keysymInHex << ") mapped to Qt::" << qtKeyName(qtKey) << " | text: " << text + << " | qt key: " << qtKey << " mapped from unicode number: " << fromUnicode; } else { - code = keysymToQtKey(keysym); + qCDebug(lcQpaKeyboard).nospace() << "no Qt::Key for keysym: " << keysymName + << "(" << keysymInHex << ") | text: " << text << " | qt key: " << qtKey; } - modifiers |= Qt::KeypadModifier; - } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f - && text.unicode()->unicode() != 0x7f - && !(keysym >= XK_dead_grave && keysym <= XK_dead_longsolidusoverlay)) { - code = text.unicode()->toUpper().unicode(); - } else { - // any other keys - code = keysymToQtKey(keysym); } - return code; + return qtKey; } QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) { - memset(&xkb_names, 0, sizeof(xkb_names)); #if QT_CONFIG(xkb) core_device_id = 0; if (connection->hasXKB()) { @@ -1539,12 +1440,8 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) QXcbKeyboard::~QXcbKeyboard() { - 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(); } void QXcbKeyboard::updateVModMapping() @@ -1890,24 +1787,36 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, // this way we allow for synthetic events to have different state // from the current state i.e. you can have Alt+Ctrl pressed // and receive a synthetic key event that has neither Alt nor Ctrl pressed - struct xkb_state *kb_state = xkb_state_new(xkb_keymap); - if (!kb_state) + ScopedXKBState xkbState(xkb_state_new(m_xkbKeymap.get())); + if (!xkbState) return; - updateXKBStateFromState(kb_state, state); + updateXKBStateFromState(xkbState.get(), state); - xcb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code); - QString string = lookupString(kb_state, code); + xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState.get(), code); + QString string = lookupString(xkbState.get(), code); - // Ιf control modifier is set we should prefer latin character, this is - // used for standard shortcuts in checks like "key == QKeySequence::Copy", - // users can still see the actual X11 keysym with QKeyEvent::nativeVirtualKey Qt::KeyboardModifiers modifiers = translateModifiers(state); - xcb_keysym_t translatedSym = XKB_KEY_NoSymbol; - if (modifiers & Qt::ControlModifier && !isLatin(sym)) - translatedSym = lookupLatinKeysym(code); - if (translatedSym == XKB_KEY_NoSymbol) - translatedSym = sym; - int qtcode = keysymToQtKey(translatedSym, modifiers, string); + if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9) + modifiers |= Qt::KeypadModifier; + + // Note 1: All standard key sequences on linux (as defined in platform theme) + // that use a latin character also contain a control modifier, which is why + // checking for Qt::ControlModifier is sufficient here. It is possible to + // override QPlatformTheme::keyBindings() and provide custom sequences for + // QKeySequence::StandardKey. Custom sequences probably should respect this + // convention (alternatively, we could test against other modifiers here). + // Note 2: The possibleKeys() shorcut mechanism is not affected by this value + // adjustment and does its own thing. + xcb_keysym_t latinKeysym = XKB_KEY_NoSymbol; + if (modifiers & Qt::ControlModifier) { + // With standard shortcuts we should prefer a latin character, this is + // in checks like "event == QKeySequence::Copy". + if (!isLatin(sym)) + latinKeysym = lookupLatinKeysym(code); + } + + int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym, + modifiers, xkbState.get(), code); bool isAutoRepeat = false; if (type == QEvent::KeyPress) { @@ -1959,7 +1868,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat); } - xkb_state_unref(kb_state); } QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const @@ -1973,6 +1881,17 @@ QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) return QString::fromUtf8(chars.constData(), size); } +QString QXcbKeyboard::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const +{ + QVarLengthArray chars(32); + const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); + if (Q_UNLIKELY(size > chars.size())) { + chars.resize(size); + xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); + } + return QString::fromUtf8(chars.constData(), size); +} + void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *event) { handleKeyEvent(event->event, QEvent::KeyPress, event->detail, event->state, event->time); diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 5cb91ed315..736b32a2fd 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -88,15 +88,12 @@ protected: void resolveMaskConflicts(); 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, const QString &text) const; - void printKeymapError(const char *error) const; + QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const; + int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, + struct xkb_state *state, xcb_keycode_t code) const; - void readXKBConfig(); - void clearXKBConfig(); -#if QT_CONFIG(xcb_xlib) struct xkb_keymap *keymapFromCore(); -#endif + // when XKEYBOARD not present on the X server void updateModifiers(); typedef QMap KeysymModifierMap; @@ -112,14 +109,8 @@ private: void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state); bool m_config = false; - bool m_keymap_is_core = false; xcb_keycode_t m_autorepeat_code = 0; - struct xkb_context *xkb_context = nullptr; - struct xkb_keymap *xkb_keymap = nullptr; - struct xkb_state *xkb_state = nullptr; - struct xkb_rule_names xkb_names; - struct _mod_masks { uint alt; uint altgr; @@ -152,7 +143,19 @@ private: struct XKBStateDeleter { void operator()(struct xkb_state *state) const { return xkb_state_unref(state); } }; + struct XKBKeymapDeleter { + void operator()(struct xkb_keymap *keymap) const { return xkb_keymap_unref(keymap); } + }; + struct XKBContextDeleter { + void operator()(struct xkb_context *context) const { return xkb_context_unref(context); } + }; using ScopedXKBState = std::unique_ptr; + using ScopedXKBKeymap = std::unique_ptr; + using ScopedXKBContext = std::unique_ptr; + + ScopedXKBState m_xkbState; + ScopedXKBKeymap m_xkbKeymap; + ScopedXKBContext m_xkbContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbxkbcommon.h b/src/plugins/platforms/xcb/qxcbxkbcommon.h new file mode 100644 index 0000000000..422c0c0f12 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbxkbcommon.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +/* XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c, + which contains the following license information: + + Copyright 1985, 1987, 1990, 1998 The Open Group + + 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 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 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. + + Except as contained in this notice, the names of the authors or their + institutions shall not be used in advertising or otherwise to promote the + sale, use or other dealings in this Software without prior written + authorization from the authors. + + + + Copyright © 2009 Dan Nicholson + + 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. +*/ + +/* + The following code modifications were applied: + + XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it + with Xlib's XConvertCase(). + + UCSConvertCase() was renamed to qt_UCSConvertCase() and function's body was + replaced to use Qt APIs for doing case conversion, which should give us better + results instead of using the less complete version from keysym.c +*/ + +#include +#include + +QT_BEGIN_NAMESPACE + +static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper) +{ + *lower = QChar::toLower(code); + *upper = QChar::toUpper(code); +} + +void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper) +{ + /* Latin 1 keysym */ + if (sym < 0x100) { + qt_UCSConvertCase(sym, lower, upper); + return; + } + + /* Unicode keysym */ + if ((sym & 0xff000000) == 0x01000000) { + qt_UCSConvertCase((sym & 0x00ffffff), lower, upper); + *upper |= 0x01000000; + *lower |= 0x01000000; + return; + } + + /* Legacy keysym */ + + *lower = sym; + *upper = sym; + + switch (sym >> 8) { + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XKB_KEY_Aogonek) + *lower = XKB_KEY_aogonek; + else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute) + *lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke); + else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute) + *lower += (XKB_KEY_scaron - XKB_KEY_Scaron); + else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot) + *lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron); + else if (sym == XKB_KEY_aogonek) + *upper = XKB_KEY_Aogonek; + else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute) + *upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke); + else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute) + *upper -= (XKB_KEY_scaron - XKB_KEY_Scaron); + else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot) + *upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron); + else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla) + *lower += (XKB_KEY_racute - XKB_KEY_Racute); + else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla) + *upper -= (XKB_KEY_racute - XKB_KEY_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex) + *lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke); + else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex) + *lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve); + else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex) + *upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke); + else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex) + *upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve); + else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex) + *lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); + else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex) + *upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash) + *lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); + else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash) + *upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); + else if (sym == XKB_KEY_ENG) + *lower = XKB_KEY_eng; + else if (sym == XKB_KEY_eng) + *upper = XKB_KEY_ENG; + else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron) + *lower += (XKB_KEY_amacron - XKB_KEY_Amacron); + else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron) + *upper -= (XKB_KEY_amacron - XKB_KEY_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE) + *lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); + else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze) + *upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); + else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN) + *lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); + else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign) + *upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent) + *lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); + else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent && + sym != XKB_KEY_Greek_iotaaccentdieresis && + sym != XKB_KEY_Greek_upsilonaccentdieresis) + *upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); + else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA) + *lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); + else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega && + sym != XKB_KEY_Greek_finalsmallsigma) + *upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); + break; + case 0x13: /* Latin 9 */ + if (sym == XKB_KEY_OE) + *lower = XKB_KEY_oe; + else if (sym == XKB_KEY_oe) + *upper = XKB_KEY_OE; + else if (sym == XKB_KEY_Ydiaeresis) + *lower = XKB_KEY_ydiaeresis; + break; + } +} + +xkb_keysym_t xkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks) +{ + xkb_keysym_t lower, upper; + + xkbcommon_XConvertCase(ks, &lower, &upper); + + return upper; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 00cce13fd0..ffc8a29116 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -46,7 +46,8 @@ HEADERS = \ qxcbcursor.h \ qxcbimage.h \ qxcbxsettings.h \ - qxcbsystemtraytracker.h + qxcbsystemtraytracker.h \ + qxcbxkbcommon.h load(qt_build_paths) diff --git a/tests/auto/corelib/global/qglobal/qglobal.c b/tests/auto/corelib/global/qglobal/qglobal.c index af42efa7f6..0719c4b921 100644 --- a/tests/auto/corelib/global/qglobal/qglobal.c +++ b/tests/auto/corelib/global/qglobal/qglobal.c @@ -110,7 +110,7 @@ Q_STATIC_ASSERT(!!1); static thread_local int gt_var; void thread_local_test() { - thread_local int t_var; + static thread_local int t_var; t_var = gt_var; } #endif