diff --git a/src/gui/kernel/qplatforminputcontextfactory.cpp b/src/gui/kernel/qplatforminputcontextfactory.cpp
index 81368a0f2555d3191ba3bcc05f06f8b32306b35b..ee80a7093949dc3ac9b6575dfea7fabe1ac8a0ec 100644
--- a/src/gui/kernel/qplatforminputcontextfactory.cpp
+++ b/src/gui/kernel/qplatforminputcontextfactory.cpp
@@ -82,8 +82,8 @@ QPlatformInputContext *QPlatformInputContextFactory::create()
 
     QString icString = QString::fromLatin1(qgetenv("QT_IM_MODULE"));
 
-    if (icString == QStringLiteral("none"))
-        return 0;
+    if (icString == QLatin1String("none"))
+        icString = QStringLiteral("compose");
 
     ic = create(icString);
     if (ic && ic->isValid())
diff --git a/src/plugins/platforminputcontexts/compose/compose.json b/src/plugins/platforminputcontexts/compose/compose.json
new file mode 100644
index 0000000000000000000000000000000000000000..2daf89ed30c67676d7cb722811dde659d3154d1b
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/compose.json
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "compose" ]
+}
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6387a47a4c55bf662ef3d9a551860947a31bac18
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/compose.pro
@@ -0,0 +1,20 @@
+TARGET = composeplatforminputcontextplugin
+
+PLUGIN_TYPE = platforminputcontexts
+PLUGIN_CLASS_NAME = QComposePlatformInputContextPlugin
+load(qt_plugin)
+
+QT += gui-private
+
+LIBS += $$QMAKE_LIBS_XKBCOMMON
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON
+
+SOURCES += $$PWD/main.cpp \
+           $$PWD/qcomposeplatforminputcontext.cpp \
+           $$PWD/generator/qtablegenerator.cpp \
+
+HEADERS += $$PWD/qcomposeplatforminputcontext.h \
+           $$PWD/generator/qtablegenerator.h \
+           $$PWD/xkbcommon_workaround.h \
+
+OTHER_FILES += $$PWD/compose.json
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5941936aec3747b5e130b0104292a45a04adfbad
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
@@ -0,0 +1,402 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtablegenerator.h"
+
+#include <QtCore/QRegularExpression>
+#include <QtCore/QByteArray>
+#include <QtCore/QTextCodec>
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+#include <QtCore/QString>
+
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon_workaround.h>
+
+#include <X11/keysym.h>
+
+//#define DEBUG_GENERATOR
+
+TableGenerator::TableGenerator() : m_state(NoErrors),
+    m_systemComposeDir(QString())
+{
+    initPossibleLocations();
+    findComposeFile();
+    orderComposeTable();
+#ifdef DEBUG_GENERATOR
+    printComposeTable();
+#endif
+}
+
+void TableGenerator::initPossibleLocations()
+{
+    // AFAICT there is no way to know the exact location
+    // of the compose files. It depends on how Xlib was configured
+    // on a specific platform. During the "./configure" process
+    // xlib generates a config.h file which contains a bunch of defines,
+    // including XLOCALEDIR which points to the location of the compose file dir.
+    // To add an extra system path use the QTCOMPOSE environment variable
+    if (qEnvironmentVariableIsSet("QTCOMPOSE")) {
+        m_possibleLocations.append(QString(qgetenv("QTCOMPOSE")));
+    }
+    m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale"));
+    m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale"));
+}
+
+void TableGenerator::findComposeFile()
+{
+    bool found = false;
+    // check if XCOMPOSEFILE points to a Compose file
+    if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) {
+        QString composeFile(qgetenv("XCOMPOSEFILE"));
+        if (composeFile.endsWith(QLatin1String("Compose")))
+            found = processFile(composeFile);
+        else
+            qWarning("Qt Warning: XCOMPOSEFILE doesn't point to a valid Compose file");
+#ifdef DEBUG_GENERATOR
+        if (found)
+            qDebug() << "Using Compose file from: " << composeFile;
+#endif
+    }
+
+    // check if user’s home directory has a file named .XCompose
+    if (!found && cleanState()) {
+        QString composeFile = qgetenv("HOME") + QStringLiteral("/.XCompose");
+        if (QFile(composeFile).exists())
+            found = processFile(composeFile);
+#ifdef DEBUG_GENERATOR
+        if (found)
+            qDebug() << "Using Compose file from: " << composeFile;
+#endif
+    }
+
+    // check for the system provided compose files
+    if (!found && cleanState()) {
+        readLocaleMappings();
+
+        if (cleanState()) {
+
+            QString table = m_localeToTable.value(locale().toUpper());
+            if (table.isEmpty())
+                // no table mappings for the system's locale in the compose.dir
+                m_state = UnsupportedLocale;
+            else
+                found = processFile(systemComposeDir() + QLatin1String("/") + table);
+#ifdef DEBUG_GENERATOR
+            if (found)
+                qDebug() << "Using Compose file from: " <<
+                            systemComposeDir() + QLatin1String("/") + table;
+#endif
+        }
+    }
+
+    if (found && m_composeTable.isEmpty())
+        m_state = EmptyTable;
+
+    if (!found)
+        m_state = MissingComposeFile;
+}
+
+bool TableGenerator::findSystemComposeDir()
+{
+    bool found = false;
+    for (int i = 0; i < m_possibleLocations.size(); ++i) {
+        QString path = m_possibleLocations.at(i);
+        if (QFile(path + QLatin1String("/compose.dir")).exists()) {
+            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);
+}
+
+void TableGenerator::readLocaleMappings()
+{
+    QFile mappings(systemComposeDir() + QLatin1String("/compose.dir"));
+    if (mappings.exists()) {
+        mappings.open(QIODevice::ReadOnly);
+        QTextStream in(&mappings);
+        // formating of compose.dir has some inconsistencies
+        while (!in.atEnd()) {
+            QString line = in.readLine();
+            if (!line.startsWith("#") && line.size() != 0 &&
+                    line.at(0).isLower()) {
+
+                QStringList pair = line.split(QRegExp(QLatin1String("\\s+")));
+                QString table = pair.at(0);
+                if (table.endsWith(QLatin1String(":")))
+                    table.remove(table.size() - 1, 1);
+
+                m_localeToTable.insert(pair.at(1).toUpper(), table);
+            }
+        }
+        mappings.close();
+    }
+}
+
+bool TableGenerator::processFile(QString composeFileName)
+{
+    QFile composeFile(composeFileName);
+    if (composeFile.exists()) {
+        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()
+{
+}
+
+QList<QComposeTableElement> TableGenerator::composeTable() const
+{
+    return m_composeTable;
+}
+
+void TableGenerator::parseComposeFile(QFile *composeFile)
+{
+#ifdef DEBUG_GENERATOR
+    qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName();
+#endif
+    QTextStream in(composeFile);
+
+    while (!in.atEnd()) {
+        QString line = in.readLine();
+        if (line.startsWith(QLatin1String("<"))) {
+            parseKeySequence(line);
+        } else if (line.startsWith(QLatin1String("include"))) {
+            parseIncludeInstruction(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"), locale());
+    line.replace(QLatin1String("%S"), systemComposeDir());
+
+    processFile(line);
+}
+
+ushort TableGenerator::keysymToUtf8(uint32_t sym)
+{
+    QByteArray chars;
+    int bytes;
+    chars.resize(8);
+
+    if (needWorkaround(sym)) {
+        uint32_t codepoint;
+        if (sym == XKB_KEY_KP_Space)
+            codepoint = XKB_KEY_space & 0x7f;
+        else
+            codepoint = sym & 0x7f;
+
+        bytes = utf32_to_utf8(codepoint, chars.data());
+    } else {
+        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
+    const QChar *ch = QString(chars.data()).unicode();
+    return ch->unicode();
+}
+
+uint32_t TableGenerator::stringToKeysym(QString keysymName)
+{
+    uint32_t keysym;
+    const char *name = keysymName.toLatin1().constData();
+
+    if ((keysym = xkb_keysym_from_name(name, (xkb_keysym_flags)0)) == XKB_KEY_NoSymbol)
+        qWarning() << QString("Qt Warrning - invalid keysym: %1").arg(keysymName);
+
+    return keysym;
+}
+
+void TableGenerator::parseKeySequence(QString line)
+{
+    // we are interested in the lines with the following format:
+    // <Multi_key> <numbersign> <S> : "♬"   U266c # BEAMED SIXTEENTH NOTE
+    int keysEnd = line.indexOf(QLatin1String(":"));
+    QString keys = line.left(keysEnd).trimmed();
+
+    // find the key sequence
+    QString regexp = QStringLiteral("<[^>]+>");
+    QRegularExpression reg(regexp);
+    QRegularExpressionMatchIterator i = reg.globalMatch(keys);
+    QStringList keyList;
+    while (i.hasNext()) {
+        QRegularExpressionMatch match = i.next();
+        QString word = match.captured(0);
+        keyList << word;
+    }
+
+    QComposeTableElement elem;
+    QString quote = QStringLiteral("\"");
+    // 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".
+    int composeValueIndex = line.indexOf(quote, keysEnd) + 1;
+    const QChar valueType(line.at(composeValueIndex));
+
+    if (valueType == '\\' && line.at(composeValueIndex + 1).isDigit()) {
+        // handle octal and hex code values
+        QChar detectBase(line.at(composeValueIndex + 2));
+        QString codeValue = line.mid(composeValueIndex + 1, line.lastIndexOf(quote) - composeValueIndex - 1);
+        if (detectBase == 'x') {
+            // hexadecimal character code
+            elem.value = keysymToUtf8(codeValue.toUInt(0, 16));
+        } else {
+            // octal character code
+            QString hexStr = QString::number(codeValue.toUInt(0, 8), 16);
+            elem.value = keysymToUtf8(hexStr.toUInt(0, 16));
+        }
+    } else {
+        // handle direct text encoded in the locale
+        elem.value = valueType.unicode();
+    }
+
+    // find the comment
+    int commnetIndex = line.lastIndexOf(quote) + 1;
+    elem.comment = line.mid(commnetIndex).trimmed();
+
+    // Convert to X11 keysym
+    int count = keyList.length();
+    for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
+        if (i < count) {
+            QString keysym = keyList.at(i);
+            keysym.remove(keysym.length() - 1, 1);
+            keysym.remove(0, 1);
+
+            if (keysym == QLatin1String("dead_inverted_breve"))
+                keysym = QStringLiteral("dead_invertedbreve");
+            else if (keysym == QLatin1String("dead_double_grave"))
+                keysym = QStringLiteral("dead_doublegrave");
+
+            elem.keys[i] = stringToKeysym(keysym);
+        } else {
+            elem.keys[i] = 0;
+        }
+    }
+    m_composeTable.append(elem);
+}
+
+void TableGenerator::printComposeTable() const
+{
+    if (composeTable().isEmpty())
+        return;
+
+    QString output;
+    QComposeTableElement elem;
+    QString comma = QStringLiteral(",");
+    int tableSize = m_composeTable.size();
+    for (int i = 0; i < tableSize; ++i) {
+        elem = m_composeTable.at(i);
+        output.append(QLatin1String("{ {"));
+        for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) {
+            output.append(QString(QLatin1String("0x%1, ")).arg(QString::number(elem.keys[j],16)));
+        }
+        // take care of the trailing comma
+        if (i == tableSize - 1)
+            comma = QStringLiteral("");
+        output.append(QString(QLatin1String("}, 0x%1, \"\" }%2 // %3 \n"))
+                      .arg(QString::number(elem.value,16))
+                      .arg(comma)
+                      .arg(elem.comment));
+    }
+
+    qDebug() << "output: \n" << output;
+}
+
+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
+    qStableSort(m_composeTable.begin(), m_composeTable.end(), Compare());
+}
+
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h
new file mode 100644
index 0000000000000000000000000000000000000000..11e7b2b42293794047689cfed52858944f510155
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTABLEGENERATOR_H
+#define QTABLEGENERATOR_H
+
+#include <QtCore/QList>
+#include <QtCore/QFile>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+
+#define QT_KEYSEQUENCE_MAX_LEN 6
+
+struct QComposeTableElement {
+    uint keys[QT_KEYSEQUENCE_MAX_LEN];
+    uint value;
+    QString comment;
+};
+
+class Compare
+{
+public:
+    bool operator () (const QComposeTableElement &lhs, const uint rhs[QT_KEYSEQUENCE_MAX_LEN])
+    {
+        for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
+            if (lhs.keys[i] != rhs[i])
+                return (lhs.keys[i] < rhs[i]);
+        }
+        return false;
+    }
+
+    bool operator () (const QComposeTableElement &lhs, const QComposeTableElement &rhs)
+    {
+        for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
+            if (lhs.keys[i] != rhs.keys[i])
+                return (lhs.keys[i] < rhs.keys[i]);
+        }
+        return false;
+    }
+};
+
+class TableGenerator
+{
+
+public:
+    enum TableState
+    {
+        UnsupportedLocale,
+        EmptyTable,
+        UnknownSystemComposeDir,
+        MissingComposeFile,
+        NoErrors
+    };
+
+    TableGenerator();
+    ~TableGenerator();
+
+    void parseComposeFile(QFile *composeFile);
+    void printComposeTable() const;
+    void orderComposeTable();
+
+    QList<QComposeTableElement> composeTable() const;
+    TableState tableState() const { return m_state; }
+
+protected:
+    bool processFile(QString composeFileName);
+    void parseKeySequence(QString line);
+    void parseIncludeInstruction(QString line);
+
+    void findComposeFile();
+    bool findSystemComposeDir();
+    QString systemComposeDir();
+
+    ushort keysymToUtf8(uint32_t sym);
+    uint32_t stringToKeysym(QString keysymName);
+
+    void readLocaleMappings();
+    void initPossibleLocations();
+    bool cleanState() const { return ((m_state & NoErrors) == NoErrors); }
+    QString locale() const;
+
+private:
+      QList<QComposeTableElement> m_composeTable;
+      QMap<QString, QString> m_localeToTable;
+      TableState m_state;
+      QString m_systemComposeDir;
+      QList<QString> m_possibleLocations;
+};
+
+#endif // QTABLEGENERATOR_H
diff --git a/src/plugins/platforminputcontexts/compose/main.cpp b/src/plugins/platforminputcontexts/compose/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..728c60caf5b2a993522b2bb1f18fa65a06f04f92
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/main.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatforminputcontextplugin_p.h>
+
+#include <QtCore/QStringList>
+
+#include "qcomposeplatforminputcontext.h"
+
+QT_BEGIN_NAMESPACE
+
+class QComposePlatformInputContextPlugin : public QPlatformInputContextPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "compose.json")
+
+public:
+    QComposeInputContext *create(const QString &, const QStringList &);
+};
+
+QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString &system, const QStringList &paramList)
+{
+    Q_UNUSED(paramList);
+
+    if (system.compare(system, QStringLiteral("compose"), Qt::CaseInsensitive) == 0)
+        return new QComposeInputContext;
+    return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..433c9eec37a18ac88e54eb5e95ca7cc61a8675c0
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcomposeplatforminputcontext.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+//#define DEBUG_COMPOSING
+
+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
+};
+
+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
+};
+
+QComposeInputContext::QComposeInputContext()
+{
+    TableGenerator reader;
+    m_tableState = reader.tableState();
+
+    if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) {
+        m_composeTable = reader.composeTable();
+        clearComposeBuffer();
+    }
+}
+
+bool QComposeInputContext::filterEvent(const QEvent *event)
+{
+    // if there were errors when generating the compose table input
+    // context should not try to filter anything, simply return false
+    if ((m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors)
+        return false;
+
+    QKeyEvent *keyEvent = (QKeyEvent *)event;
+    // should pass only the key presses
+    if (keyEvent->type() != QEvent::KeyPress) {
+        return false;
+    }
+
+    int keyval = keyEvent->key();
+    int keysym = 0;
+
+    if (ignoreKey(keyval))
+        return false;
+
+    QString text = keyEvent->text();
+    if (!composeKey(keyval) && text.isEmpty())
+        return false;
+
+    keysym = keyEvent->nativeVirtualKey();
+
+    int nCompose = 0;
+    while (m_composeBuffer[nCompose] != 0 && nCompose < QT_KEYSEQUENCE_MAX_LEN)
+        nCompose++;
+
+    if (nCompose == QT_KEYSEQUENCE_MAX_LEN) {
+        reset();
+        nCompose = 0;
+    }
+
+    m_composeBuffer[nCompose] = keysym;
+    // check sequence
+    if (checkComposeTable())
+        return true;
+
+    return false;
+}
+
+bool QComposeInputContext::isValid() const
+{
+    return true;
+}
+
+void QComposeInputContext::setFocusObject(QObject *object)
+{
+    m_focusObject = object;
+}
+
+void QComposeInputContext::reset()
+{
+    clearComposeBuffer();
+}
+
+void QComposeInputContext::update(Qt::InputMethodQueries q)
+{
+    QPlatformInputContext::update(q);
+}
+
+static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs)
+{
+    for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
+        if (lhs.keys[i] != rhs.keys[i])
+            return false;
+    }
+    return true;
+}
+
+bool QComposeInputContext::checkComposeTable()
+{
+    QList<QComposeTableElement>::iterator it =
+            qLowerBound(m_composeTable.begin(), m_composeTable.end(), m_composeBuffer, Compare());
+
+    // prevent dereferencing an 'end' iterator, which would result in a crash
+    if (it == m_composeTable.end())
+        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.end()) {
+            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
new file mode 100644
index 0000000000000000000000000000000000000000..1ced2f8ded39807f0ccd3d723196796730788d75
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H
+#define QCOMPOSEPLATFORMINPUTCONTEXT_H
+
+#include <qpa/qplatforminputcontext.h>
+
+#include <QtCore/QList>
+
+#include "generator/qtablegenerator.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+
+class QComposeInputContext : public QPlatformInputContext
+{
+    Q_OBJECT
+
+public:
+    QComposeInputContext();
+    ~QComposeInputContext();
+
+    bool isValid() const;
+    void setFocusObject(QObject *object);
+    void reset();
+    void update(Qt::InputMethodQueries);
+    bool filterEvent(const QEvent *event);
+
+protected:
+    void clearComposeBuffer();
+    bool ignoreKey(int keyval) const;
+    bool composeKey(int keyval) const;
+    bool checkComposeTable();
+    void commitText(uint character) const;
+
+private:
+    QObject *m_focusObject;
+    QList<QComposeTableElement> m_composeTable;
+    uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN + 1];
+    TableGenerator::TableState m_tableState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOMPOSEPLATFORMINPUTCONTEXT_H
diff --git a/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h b/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h
new file mode 100644
index 0000000000000000000000000000000000000000..58ce143978f0be963d7f1c337554afced13f8299
--- /dev/null
+++ b/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XKBCOMMON_WORKAROUND_H
+#define XKBCOMMON_WORKAROUND_H
+
+// Function utf32_to_utf8() is borrowed from the libxkbcommon library,
+// file keysym-utf.c. The workaround should be removed once the fix from
+// https://bugs.freedesktop.org/show_bug.cgi?id=56780 gets released.
+static int utf32_to_utf8(uint32_t unichar, char *buffer)
+{
+    int count, shift, length;
+    uint8_t head;
+
+    if (unichar <= 0x007f) {
+        buffer[0] = unichar;
+        buffer[1] = '\0';
+        return 2;
+    }
+    else if (unichar <= 0x07FF) {
+        length = 2;
+        head = 0xc0;
+    }
+    else if (unichar <= 0xffff) {
+        length = 3;
+        head = 0xe0;
+    }
+    else if (unichar <= 0x1fffff) {
+        length = 4;
+        head = 0xf0;
+    }
+    else if (unichar <= 0x3ffffff) {
+        length = 5;
+        head = 0xf8;
+    }
+    else {
+        length = 6;
+        head = 0xfc;
+    }
+
+    for (count = length - 1, shift = 0; count > 0; count--, shift += 6)
+        buffer[count] = 0x80 | ((unichar >> shift) & 0x3f);
+
+    buffer[0] = head | ((unichar >> shift) & 0x3f);
+    buffer[length] = '\0';
+
+    return length + 1;
+}
+
+static bool needWorkaround(uint32_t sym)
+{
+    /* patch encoding botch */
+    if (sym == XKB_KEY_KP_Space)
+        return true;
+
+    /* special keysyms */
+    if ((sym >= XKB_KEY_BackSpace && sym <= XKB_KEY_Clear) ||
+        (sym >= XKB_KEY_KP_Multiply && sym <= XKB_KEY_KP_9) ||
+        sym == XKB_KEY_Return || sym == XKB_KEY_Escape ||
+        sym == XKB_KEY_Delete || sym == XKB_KEY_KP_Tab ||
+        sym == XKB_KEY_KP_Enter || sym == XKB_KEY_KP_Equal)
+        return true;
+
+    return false;
+}
+
+#endif // XKBCOMMON_WORKAROUND_H
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
index 7b3c6e9c36acd1075461d7c5d346ffdd6d6aed80..fb58de5edc20743748d99be6ccaac212cdf6b7fd 100644
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
@@ -1,4 +1,10 @@
 TEMPLATE = subdirs
+
 qtHaveModule(dbus) {
 !mac:!win32:SUBDIRS += ibus maliit
 }
+
+unix:!macx:contains(QT_CONFIG, xkbcommon): {
+    SUBDIRS += compose
+}
+