ibus IM support for the xcb backend
authorLars Knoll <lars.knoll@nokia.com>
Wed, 22 Jun 2011 08:01:14 +0000 (10:01 +0200)
committerLars Knoll <lars.knoll@nokia.com>
Mon, 27 Jun 2011 12:31:15 +0000 (14:31 +0200)
Test code to check input methods using the ibus backend
used on e.g. ubuntu. The IM code is not very sophisticated,
but enough to test that things are working.

Reviewed-by: Jørgen Lind
18 files changed:
src/platformsupport/inputmethods/ibus/ibus.pri [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.InputContext.xml [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.xml [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.cpp [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.h [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.cpp [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.h [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusproxy.cpp [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibusproxy.h [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibustypes.cpp [new file with mode: 0644]
src/platformsupport/inputmethods/ibus/qibustypes.h [new file with mode: 0644]
src/platformsupport/inputmethods/inputmethods.pri [new file with mode: 0644]
src/platformsupport/platformsupport.pro
src/plugins/platforms/xcb/qxcbintegration.cpp
src/plugins/platforms/xcb/qxcbintegration.h
src/plugins/platforms/xcb/qxcbkeyboard.cpp
src/plugins/platforms/xcb/xcb.pro
src/widgets/kernel/qwidget.cpp

diff --git a/src/platformsupport/inputmethods/ibus/ibus.pri b/src/platformsupport/inputmethods/ibus/ibus.pri
new file mode 100644 (file)
index 0000000..c6e59aa
--- /dev/null
@@ -0,0 +1,11 @@
+QT += dbus
+
+SOURCES += $$PWD/qibusplatforminputcontext.cpp \
+        $$PWD/qibusproxy.cpp \
+        $$PWD/qibusinputcontextproxy.cpp \
+        $$PWD/qibustypes.cpp
+
+HEADERS += $$PWD/qibusplatforminputcontext.h \
+        $$PWD/qibusproxy.h \
+        $$PWD/qibusinputcontextproxy.h \
+        $$PWD/qibustypes.h
diff --git a/src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
new file mode 100644 (file)
index 0000000..dbc79c1
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.freedesktop.IBus.InputContext">
+    <method name="ProcessKeyEvent">
+      <arg name="keyval" direction="in" type="u"/>
+      <arg name="keycode" direction="in" type="u"/>
+      <arg name="state" direction="in" type="u"/>
+      <arg name="handled" direction="out" type="b"/>
+    </method>
+    <method name="SetCursorLocation">
+      <arg name="x" direction="in" type="i"/>
+      <arg name="y" direction="in" type="i"/>
+      <arg name="w" direction="in" type="i"/>
+      <arg name="h" direction="in" type="i"/>
+    </method>
+    <method name="FocusIn"/>
+    <method name="FocusOut"/>
+    <method name="Reset"/>
+    <method name="Enable"/>
+    <method name="Disable"/>
+    <method name="IsEnabled">
+      <arg name="enable" direction="out" type="b"/>
+    </method>
+    <method name="SetCapabilities">
+      <arg name="caps" direction="in" type="u"/>
+    </method>
+    <method name="PropertyActivate">
+      <arg name="name" direction="in" type="s"/>
+      <arg name="state" direction="in" type="i"/>
+    </method>
+    <method name="SetEngine">
+      <arg name="name" direction="in" type="s"/>
+    </method>
+    <method name="GetEngine">
+      <arg name="desc" direction="out" type="v"/>
+    </method>
+    <method name="Destroy"/>
+    <signal name="CommitText">
+      <arg name="text" type="v"/>
+    </signal>
+    <signal name="Enabled"/>
+    <signal name="Disabled"/>
+    <signal name="ForwardKeyEvent">
+      <arg name="keyval" type="u"/>
+      <arg name="keycode" type="u"/>
+      <arg name="state" type="u"/>
+    </signal>
+    <signal name="UpdatePreeditText">
+      <arg name="text" type="v"/>
+      <arg name="cursor_pos" type="u"/>
+      <arg name="visible" type="b"/>
+    </signal>
+    <signal name="ShowPreeditText"/>
+    <signal name="HidePreeditText"/>
+    <signal name="UpdateAuxiliaryText">
+      <arg name="text" type="v"/>
+      <arg name="visible" type="b"/>
+    </signal>
+    <signal name="ShowAuxiliaryText"/>
+    <signal name="HideAuxiliaryText"/>
+    <signal name="UpdateLookupTable">
+      <arg name="table" type="v"/>
+      <arg name="visible" type="b"/>
+    </signal>
+    <signal name="ShowLookupTable"/>
+    <signal name="HideLookupTable"/>
+    <signal name="PageUpLookupTable"/>
+    <signal name="PageDownLookupTable"/>
+    <signal name="CursorUpLookupTable"/>
+    <signal name="CursorDownLookupTable"/>
+    <signal name="RegisterProperties">
+      <arg name="props" type="v"/>
+    </signal>
+    <signal name="UpdateProperty">
+      <arg name="prop" type="v"/>
+    </signal>
+  </interface>
+</node>
+
diff --git a/src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.xml b/src/platformsupport/inputmethods/ibus/interfaces/org.freedesktop.IBus.xml
new file mode 100644 (file)
index 0000000..6ac4891
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.freedesktop.IBus">
+    <method name="GetAddress">
+      <arg name="address" direction="out" type="s"/>
+    </method>
+    <method name="CreateInputContext">
+      <arg name="name" direction="in" type="s"/>
+      <arg name="context" direction="out" type="o"/>
+    </method>
+    <method name="RegisterComponent">
+      <arg name="components" direction="in" type="v"/>
+    </method>
+    <method name="ListEngines">
+      <arg name="engines" direction="out" type="av"/>
+    </method>
+    <method name="ListActiveEngines">
+      <arg name="engines" direction="out" type="av"/>
+    </method>
+    <method name="Exit">
+      <arg name="restart" direction="in" type="b"/>
+    </method>
+    <method name="Ping">
+      <arg name="data" direction="in" type="v"/>
+      <arg name="data" direction="out" type="v"/>
+    </method>
+  </interface>
+</node>
+
diff --git a/src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.cpp b/src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.cpp
new file mode 100644 (file)
index 0000000..7adffbc
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "qibusinputcontextproxy.h"
+
+/*
+ * Implementation of interface class QIBusInputContextProxy
+ */
+
+QIBusInputContextProxy::QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+    : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+QIBusInputContextProxy::~QIBusInputContextProxy()
+{
+}
+
diff --git a/src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.h b/src/platformsupport/inputmethods/ibus/qibusinputcontextproxy.h
new file mode 100644 (file)
index 0000000..9a91c4e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef QIBUSINPUTCONTEXTPROXY_H_1308831153
+#define QIBUSINPUTCONTEXTPROXY_H_1308831153
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+
+/*
+ * Proxy class for interface org.freedesktop.IBus.InputContext
+ */
+class QIBusInputContextProxy: public QDBusAbstractInterface
+{
+    Q_OBJECT
+public:
+    static inline const char *staticInterfaceName()
+    { return "org.freedesktop.IBus.InputContext"; }
+
+public:
+    QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+
+    ~QIBusInputContextProxy();
+
+public Q_SLOTS: // METHODS
+    inline QDBusPendingReply<> Destroy()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("Destroy"), argumentList);
+    }
+
+    inline QDBusPendingReply<> Disable()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("Disable"), argumentList);
+    }
+
+    inline QDBusPendingReply<> Enable()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("Enable"), argumentList);
+    }
+
+    inline QDBusPendingReply<> FocusIn()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("FocusIn"), argumentList);
+    }
+
+    inline QDBusPendingReply<> FocusOut()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("FocusOut"), argumentList);
+    }
+
+    inline QDBusPendingReply<QDBusVariant> GetEngine()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("GetEngine"), argumentList);
+    }
+
+    inline QDBusPendingReply<bool> IsEnabled()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("IsEnabled"), argumentList);
+    }
+
+    inline QDBusPendingReply<bool> ProcessKeyEvent(uint keyval, uint keycode, uint state)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state);
+        return asyncCallWithArgumentList(QLatin1String("ProcessKeyEvent"), argumentList);
+    }
+
+    inline QDBusPendingReply<> PropertyActivate(const QString &name, int state)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(name) << QVariant::fromValue(state);
+        return asyncCallWithArgumentList(QLatin1String("PropertyActivate"), argumentList);
+    }
+
+    inline QDBusPendingReply<> Reset()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("Reset"), argumentList);
+    }
+
+    inline QDBusPendingReply<> SetCapabilities(uint caps)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(caps);
+        return asyncCallWithArgumentList(QLatin1String("SetCapabilities"), argumentList);
+    }
+
+    inline QDBusPendingReply<> SetCursorLocation(int x, int y, int w, int h)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
+        return asyncCallWithArgumentList(QLatin1String("SetCursorLocation"), argumentList);
+    }
+
+    inline QDBusPendingReply<> SetEngine(const QString &name)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(name);
+        return asyncCallWithArgumentList(QLatin1String("SetEngine"), argumentList);
+    }
+
+Q_SIGNALS: // SIGNALS
+    void CommitText(const QDBusVariant &text);
+    void CursorDownLookupTable();
+    void CursorUpLookupTable();
+    void Disabled();
+    void Enabled();
+    void ForwardKeyEvent(uint keyval, uint keycode, uint state);
+    void HideAuxiliaryText();
+    void HideLookupTable();
+    void HidePreeditText();
+    void PageDownLookupTable();
+    void PageUpLookupTable();
+    void RegisterProperties(const QDBusVariant &props);
+    void ShowAuxiliaryText();
+    void ShowLookupTable();
+    void ShowPreeditText();
+    void UpdateAuxiliaryText(const QDBusVariant &text, bool visible);
+    void UpdateLookupTable(const QDBusVariant &table, bool visible);
+    void UpdatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+    void UpdateProperty(const QDBusVariant &prop);
+};
+
+#endif
diff --git a/src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.cpp b/src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.cpp
new file mode 100644 (file)
index 0000000..f0a3270
--- /dev/null
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qibusplatforminputcontext.h"
+
+#include <QtDebug>
+#include <QTextCharFormat>
+#include <QGuiApplication>
+#include <qevent.h>
+
+#include "qibusproxy.h"
+#include "qibusinputcontextproxy.h"
+#include "qibustypes.h"
+
+#include <sys/types.h>
+#include <signal.h>
+
+#include <QtDBus>
+
+class QIBusPlatformInputContextPrivate
+{
+public:
+    QIBusPlatformInputContextPrivate();
+    ~QIBusPlatformInputContextPrivate()
+    {
+        delete context;
+        delete bus;
+        delete connection;
+    }
+
+    static QDBusConnection *createConnection();
+
+    QDBusConnection *connection;
+    QIBusProxy *bus;
+    QIBusInputContextProxy *context;
+
+    bool valid;
+};
+
+
+QIBusPlatformInputContext::QIBusPlatformInputContext ()
+    : d(new QIBusPlatformInputContextPrivate())
+{
+    connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
+    connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
+}
+
+QIBusPlatformInputContext::~QIBusPlatformInputContext (void)
+{
+    delete d;
+}
+
+void QIBusPlatformInputContext::mouseHandler (int x, QMouseEvent *event)
+{
+    QPlatformInputContext::mouseHandler (x, event);
+
+    if (!d->valid)
+        return;
+}
+
+void QIBusPlatformInputContext::reset()
+{
+    QPlatformInputContext::reset();
+
+    if (!d->valid)
+        return;
+
+    d->context->Reset();
+}
+
+void QIBusPlatformInputContext::update()
+{
+    QPlatformInputContext::update();
+
+    if (!d->valid)
+        return;
+
+    QObject *o = focusObject();
+    if (!o)
+        return;
+
+    QInputMethodQueryEvent query(Qt::ImMicroFocus);
+    QGuiApplication::sendEvent(o, &query);
+    QRect r = query.value().toRect();
+    if(r.isValid()) {
+        qDebug() << "mocroFocus" << r;
+        d->context->SetCursorLocation(r.x(), r.y(), r.width(), r.height());
+    }
+}
+
+void QIBusPlatformInputContext::setFocusObject(QObject *object)
+{
+    QPlatformInputContext::setFocusObject(object);
+
+    if (!d->valid)
+        return;
+
+    qDebug() << "setFocusObject" << object;
+    if (object)
+        d->context->FocusIn();
+    else
+        d->context->FocusOut();
+}
+
+
+void QIBusPlatformInputContext::commitText(const QDBusVariant &text)
+{
+    const QDBusArgument arg = text.variant().value<QDBusArgument>();
+
+    QIBusText t;
+    qDebug() << arg.currentSignature();
+    t.fromDBusArgument(arg);
+    qDebug() << "commit text:" << t.text;
+
+    QInputMethodEvent event;
+    event.setCommitString(t.text);
+    QCoreApplication::sendEvent(focusObject(), &event);
+}
+
+void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint cursorPos, bool visible)
+{
+    const QDBusArgument arg = text.variant().value<QDBusArgument>();
+
+    QIBusText t;
+    t.fromDBusArgument(arg);
+    qDebug() << "preedit text:" << t.text;
+
+    QList<QInputMethodEvent::Attribute> attributes = t.attributes.imAttributes();
+    attributes += QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, visible ? 1 : 0, QVariant());
+
+    QInputMethodEvent event(t.text, attributes);
+    QCoreApplication::sendEvent(focusObject(), &event);
+}
+
+
+/* Kernel keycode -> X keycode table */
+static const unsigned int keycode_table[256] = {
+      0,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 22,  23,
+     24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 54,  55,
+     56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 70,  71,
+     72,  73,  74,  75,  76,  77,  76,  79,  80,  81,  82,  83,  84,  85, 86,  87,
+     88,  89,  90,  91, 111,  221, 94,  95,  96, 211, 128, 127, 129, 208, 131, 126,
+    108, 109, 112, 111, 113, 181,  97,  98,  99, 100, 102, 103, 104, 105, 106, 107,
+    239, 160, 174, 176, 222, 157, 123, 110, 139, 134, 209, 210, 133, 115, 116, 117,
+    232, 133, 134, 135, 140, 248, 191, 192, 122, 188, 245, 158, 161, 193, 223, 227,
+    198, 199, 200, 147, 159, 151, 178, 201, 146, 203, 166, 236, 230, 235, 234, 233,
+    163, 204, 253, 153, 162, 144, 164, 177, 152, 190, 208, 129, 130, 231, 209, 210,
+    136, 220, 143, 246, 251, 137, 138, 182, 183, 184,  93, 184, 247, 132, 170, 219,
+    249, 205, 207, 149, 150, 154, 155, 167, 168, 169, 171, 172, 173, 165, 175, 179,
+    180,   0, 185, 186, 187, 118, 119, 120, 121, 229, 194, 195, 196, 197, 148, 202,
+    101, 212, 237, 214, 215, 216, 217, 218, 228, 142, 213, 240, 241, 242, 243, 244,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
+};
+
+bool
+QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press)
+{
+    if (!d->valid)
+        return false;
+
+    if (!press)
+        return false;
+
+    keycode -= 8; // ###
+    QDBusReply<bool> reply = d->context->ProcessKeyEvent(keyval, keycode, state);
+
+//    qDebug() << "x11FilterEvent return" << reply.value();
+
+    return reply.value();
+}
+
+QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
+    : connection(createConnection()),
+      bus(0),
+      context(0),
+      valid(false)
+{
+    if (!connection->isConnected()) {
+        qDebug() << "not connected";
+        return;
+    }
+
+    bus = new QIBusProxy(QLatin1String("org.freedesktop.IBus"),
+                         QLatin1String("/org/freedesktop/IBus"),
+                         *connection);
+    if (!bus->isValid()) {
+        qDebug() << "invalid bus";
+        return;
+    }
+
+    QDBusReply<QDBusObjectPath> ic = bus->CreateInputContext(QLatin1String("QIBusInputContext"));
+    if (!ic.isValid()) {
+        qDebug() << "CreateInputContext failed";
+        return;
+    }
+
+    context = new QIBusInputContextProxy(QLatin1String("org.freedesktop.IBus"), ic.value().path(), *connection);
+
+    if (!context->isValid()) {
+        qDebug() << "invalid input context";
+        return;
+    }
+
+    enum Capabilities {
+        IBUS_CAP_PREEDIT_TEXT       = 1 << 0,
+        IBUS_CAP_AUXILIARY_TEXT     = 1 << 1,
+        IBUS_CAP_LOOKUP_TABLE       = 1 << 2,
+        IBUS_CAP_FOCUS              = 1 << 3,
+        IBUS_CAP_PROPERTY           = 1 << 4,
+        IBUS_CAP_SURROUNDING_TEXT   = 1 << 5,
+    };
+    context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS);
+
+    qDebug() << ">>>> valid!";
+    valid = true;
+}
+
+QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+{
+    QByteArray display(getenv("DISPLAY"));
+    QByteArray host = "unix";
+    QByteArray displayNumber = "0";
+
+    int pos = display.indexOf(':');
+    if (pos > 0)
+        host = display.left(pos);
+    ++pos;
+    int pos2 = display.indexOf('.', pos);
+    if (pos2 > 0)
+        displayNumber = display.mid(pos, pos2 - pos);
+    qDebug() << "host=" << host << "displayNumber" << displayNumber;
+
+    QFile file(QDir::homePath() + QLatin1String("/.config/ibus/bus/") +
+               QLatin1String(QDBusConnection::localMachineId()) +
+               QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber));
+
+    if (!file.exists()) {
+        qDebug() << "ibus config file does not exist";
+        return 0;
+    }
+
+    file.open(QFile::ReadOnly);
+
+    QByteArray address;
+    int pid = -1;
+
+    while (!file.atEnd()) {
+        QByteArray line = file.readLine().trimmed();
+        if (line.startsWith('#'))
+            continue;
+
+        if (line.startsWith("IBUS_ADDRESS="))
+            address = line.mid(sizeof("IBUS_ADDRESS=") - 1);
+        if (line.startsWith("IBUS_DAEMON_PID="))
+            pid = line.mid(sizeof("IBUS_DAEMON_PID=") - 1).toInt();
+    }
+
+    qDebug() << "IBUS_ADDRESS=" << address << "PID=" << pid;
+    if (address.isEmpty() || pid < 0 || kill(pid, 0) != 0)
+        return 0;
+
+    return new QDBusConnection(QDBusConnection::connectToBus(QString::fromLatin1(address), QLatin1String("QIBusProxy")));
+}
diff --git a/src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.h b/src/platformsupport/inputmethods/ibus/qibusplatforminputcontext.h
new file mode 100644 (file)
index 0000000..6912fe4
--- /dev/null
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QIBUSPLATFORMINPUTCONTEXT_H
+#define QIBUSPLATFORMINPUTCONTEXT_H
+
+#include <QPlatformInputContext>
+
+class QIBusPlatformInputContextPrivate;
+class QDBusVariant;
+
+class QIBusPlatformInputContext : public QObject, public QPlatformInputContext
+{
+    Q_OBJECT
+public:
+    QIBusPlatformInputContext();
+    ~QIBusPlatformInputContext();
+
+    void mouseHandler(int x, QMouseEvent *event);
+    void reset(void);
+    void update(void);
+    void setFocusObject(QObject *object);
+
+    bool x11FilterEvent(uint keyval, uint keycode, uint state, bool press);
+
+public Q_SLOTS:
+    void commitText(const QDBusVariant &text);
+    void updatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+
+private:
+    QIBusPlatformInputContextPrivate *d;
+};
+
+#endif
diff --git a/src/platformsupport/inputmethods/ibus/qibusproxy.cpp b/src/platformsupport/inputmethods/ibus/qibusproxy.cpp
new file mode 100644 (file)
index 0000000..9d64b60
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -N -p qibusproxy -c QIBusProxy interfaces/org.freedesktop.IBus.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "qibusproxy.h"
+
+/*
+ * Implementation of interface class QIBusProxy
+ */
+
+QIBusProxy::QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+    : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+QIBusProxy::~QIBusProxy()
+{
+}
+
diff --git a/src/platformsupport/inputmethods/ibus/qibusproxy.h b/src/platformsupport/inputmethods/ibus/qibusproxy.h
new file mode 100644 (file)
index 0000000..389eec3
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -N -p qibusproxy -c QIBusProxy interfaces/org.freedesktop.IBus.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef QIBUSPROXY_H_1308831142
+#define QIBUSPROXY_H_1308831142
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+
+/*
+ * Proxy class for interface org.freedesktop.IBus
+ */
+class QIBusProxy: public QDBusAbstractInterface
+{
+    Q_OBJECT
+public:
+    static inline const char *staticInterfaceName()
+    { return "org.freedesktop.IBus"; }
+
+public:
+    QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+
+    ~QIBusProxy();
+
+public Q_SLOTS: // METHODS
+    inline QDBusPendingReply<QDBusObjectPath> CreateInputContext(const QString &name)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(name);
+        return asyncCallWithArgumentList(QLatin1String("CreateInputContext"), argumentList);
+    }
+
+    inline QDBusPendingReply<> Exit(bool restart)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(restart);
+        return asyncCallWithArgumentList(QLatin1String("Exit"), argumentList);
+    }
+
+    inline QDBusPendingReply<QString> GetAddress()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("GetAddress"), argumentList);
+    }
+
+    inline QDBusPendingReply<QVariantList> ListActiveEngines()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("ListActiveEngines"), argumentList);
+    }
+
+    inline QDBusPendingReply<QVariantList> ListEngines()
+    {
+        QList<QVariant> argumentList;
+        return asyncCallWithArgumentList(QLatin1String("ListEngines"), argumentList);
+    }
+
+    inline QDBusPendingReply<QDBusVariant> Ping(const QDBusVariant &data)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(data);
+        return asyncCallWithArgumentList(QLatin1String("Ping"), argumentList);
+    }
+
+    inline QDBusPendingReply<> RegisterComponent(const QDBusVariant &components)
+    {
+        QList<QVariant> argumentList;
+        argumentList << QVariant::fromValue(components);
+        return asyncCallWithArgumentList(QLatin1String("RegisterComponent"), argumentList);
+    }
+
+Q_SIGNALS: // SIGNALS
+};
+
+#endif
diff --git a/src/platformsupport/inputmethods/ibus/qibustypes.cpp b/src/platformsupport/inputmethods/ibus/qibustypes.cpp
new file mode 100644 (file)
index 0000000..8d8c61a
--- /dev/null
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qibustypes.h"
+#include <qtextformat.h>
+#include <QtDBus>
+
+QIBusSerializable::QIBusSerializable()
+{
+}
+
+QIBusSerializable::~QIBusSerializable()
+{
+}
+
+void QIBusSerializable::fromDBusArgument(const QDBusArgument &arg)
+{
+    arg >> name;
+    arg.beginMap();
+    while (!arg.atEnd()) {
+        arg.beginMapEntry();
+        QString key;
+        QDBusVariant value;
+        arg >> key;
+        arg >> value;
+        arg.endMapEntry();
+        attachments[key] = value.variant().value<QDBusArgument>();
+    }
+    arg.endMap();
+}
+
+
+
+QIBusAttribute::QIBusAttribute()
+    : type(Invalid),
+      value(0),
+      start(0),
+      end(0)
+{
+}
+
+QIBusAttribute::~QIBusAttribute()
+{
+
+}
+
+void QIBusAttribute::fromDBusArgument(const QDBusArgument &arg)
+{
+//    qDebug() << "QIBusAttribute::fromDBusArgument()" << arg.currentSignature();
+    arg.beginStructure();
+
+    QIBusSerializable::fromDBusArgument(arg);
+
+    quint32 t;
+    arg >> t;
+    type = (Type)t;
+    arg >> value;
+    arg >> start;
+    arg >> end;
+
+    arg.endStructure();
+}
+
+QTextFormat QIBusAttribute::format() const
+{
+    QTextCharFormat fmt;
+    switch (type) {
+    case Invalid:
+        break;
+    case Underline: {
+        QTextCharFormat::UnderlineStyle style = QTextCharFormat::NoUnderline;
+
+        switch (value) {
+        case UnderlineNone:
+            break;
+        case UnderlineSingle:
+            style = QTextCharFormat::SingleUnderline;
+            break;
+        case UnderlineDouble:
+            style = QTextCharFormat::DashUnderline;
+            break;
+        case UnderlineLow:
+            style = QTextCharFormat::DashDotLine;
+            break;
+        case UnderlineError:
+            style = QTextCharFormat::WaveUnderline;
+            fmt.setUnderlineColor(Qt::red);
+            break;
+        }
+
+        fmt.setUnderlineStyle(style);
+        break;
+    }
+    case Foreground:
+        fmt.setForeground(QColor(value));
+        break;
+    case Background:
+        fmt.setBackground(QColor(value));
+        break;
+    }
+    return fmt;
+}
+
+
+QIBusAttributeList::QIBusAttributeList()
+{
+
+}
+
+QIBusAttributeList::~QIBusAttributeList()
+{
+
+}
+
+void QIBusAttributeList::fromDBusArgument(const QDBusArgument &arg)
+{
+//    qDebug() << "QIBusAttributeList::fromDBusArgument()" << arg.currentSignature();
+    arg.beginStructure();
+
+    QIBusSerializable::fromDBusArgument(arg);
+
+    arg.beginArray();
+    while(!arg.atEnd()) {
+        QDBusVariant var;
+        arg >> var;
+
+        QIBusAttribute attr;
+        attr.fromDBusArgument(var.variant().value<QDBusArgument>());
+        attributes.append(attr);
+    }
+    arg.endArray();
+
+    arg.endStructure();
+}
+
+QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const
+{
+    QList<QInputMethodEvent::Attribute> imAttrs;
+    for (int i = 0; i < attributes.size(); ++i) {
+        const QIBusAttribute &attr = attributes.at(i);
+        imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, attr.start, attr.end - attr.start, attr.format());
+    }
+    return imAttrs;
+}
+
+
+QIBusText::QIBusText()
+{
+
+}
+
+QIBusText::~QIBusText()
+{
+
+}
+
+void QIBusText::fromDBusArgument(const QDBusArgument &arg)
+{
+//    qDebug() << "QIBusText::fromDBusArgument()" << arg.currentSignature();
+    arg.beginStructure();
+
+    QIBusSerializable::fromDBusArgument(arg);
+
+    arg >> text;
+    QDBusVariant variant;
+    arg >> variant;
+    attributes.fromDBusArgument(variant.variant().value<QDBusArgument>());
+
+    arg.endStructure();
+}
+
diff --git a/src/platformsupport/inputmethods/ibus/qibustypes.h b/src/platformsupport/inputmethods/ibus/qibustypes.h
new file mode 100644 (file)
index 0000000..c426ff7
--- /dev/null
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QIBUSTYPES_H
+#define QIBUSTYPES_H
+
+#include <qvector.h>
+#include <qevent.h>
+
+class QDBusArgument;
+
+class QIBusSerializable
+{
+public:
+    QIBusSerializable();
+    virtual ~QIBusSerializable();
+
+    virtual void fromDBusArgument(const QDBusArgument &arg);
+
+    QString name;
+    QHash<QString, QDBusArgument>  attachments;
+};
+
+class QIBusAttribute : public QIBusSerializable
+{
+public:
+    enum Type {
+        Invalid = 0,
+        Underline = 1,
+        Foreground = 2,
+        Background = 3,
+    };
+
+    enum Underline {
+        UnderlineNone = 0,
+        UnderlineSingle  = 1,
+        UnderlineDouble  = 2,
+        UnderlineLow = 3,
+        UnderlineError = 4,
+    };
+
+    QIBusAttribute();
+    ~QIBusAttribute();
+
+    void fromDBusArgument(const QDBusArgument &arg);
+    QTextFormat format() const;
+
+    Type type;
+    quint32 value;
+    quint32 start;
+    quint32 end;
+};
+
+class QIBusAttributeList : public QIBusSerializable
+{
+public:
+    QIBusAttributeList();
+    ~QIBusAttributeList();
+
+    void fromDBusArgument(const QDBusArgument &arg);
+
+    QList<QInputMethodEvent::Attribute> imAttributes() const;
+
+    QVector<QIBusAttribute> attributes;
+};
+
+class QIBusText : public QIBusSerializable
+{
+public:
+    QIBusText();
+    ~QIBusText();
+
+    void fromDBusArgument(const QDBusArgument &arg);
+
+    QString text;
+    QIBusAttributeList attributes;
+};
+
+#endif
diff --git a/src/platformsupport/inputmethods/inputmethods.pri b/src/platformsupport/inputmethods/inputmethods.pri
new file mode 100644 (file)
index 0000000..93042b7
--- /dev/null
@@ -0,0 +1,3 @@
+unix {
+    include($$PWD/ibus/ibus.pri)
+}
index ed6c408..0f83a8e 100644 (file)
@@ -27,4 +27,4 @@ include(fb_base/fb_base.pri)
 include(fontdatabases/fontdatabases.pri)
 include(glxconvenience/glxconvenience.pri)
 include(printersupport/printersupport.pri)
-#include(inputmethods/inputmethods.pri)
+include(inputmethods/inputmethods.pri)
index 984c8af..fcc17b2 100644 (file)
 #include <QtPlatformSupport/private/qeglplatformcontext_p.h>
 #endif
 
+#define XCB_USE_IBUS
+#if defined(XCB_USE_IBUS)
+#include "QtPlatformSupport/qibusplatforminputcontext.h"
+#endif
+
 QXcbIntegration::QXcbIntegration()
     : m_connection(new QXcbConnection), m_printerSupport(new QGenericUnixPrinterSupport)
 {
@@ -79,6 +84,8 @@ QXcbIntegration::QXcbIntegration()
 
     m_fontDatabase = new QGenericUnixFontDatabase();
     m_nativeInterface = new QXcbNativeInterface;
+
+    m_inputContext = 0;
 }
 
 QXcbIntegration::~QXcbIntegration()
@@ -141,6 +148,11 @@ QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const
 {
     QAbstractEventDispatcher *eventDispatcher = createUnixEventDispatcher();
     m_connection->setEventDispatcher(eventDispatcher);
+#ifdef XCB_USE_IBUS
+    // A bit hacky to do this here, but we need an eventloop before we can instantiate
+    // the input context.
+    const_cast<QXcbIntegration *>(this)->m_inputContext = new QIBusPlatformInputContext;
+#endif
     return eventDispatcher;
 }
 
@@ -318,3 +330,8 @@ QPlatformDrag *QXcbIntegration::drag() const
 {
     return m_connection->drag();
 }
+
+QPlatformInputContext *QXcbIntegration::inputContext() const
+{
+    return m_inputContext;
+}
index 1f426ab..a89ffc8 100644 (file)
@@ -76,6 +76,8 @@ public:
     QPlatformClipboard *clipboard() const;
     QPlatformDrag *drag() const;
 
+    QPlatformInputContext *inputContext() const;
+
 private:
     bool hasOpenGL() const;
     QList<QPlatformScreen *> m_screens;
@@ -84,6 +86,8 @@ private:
     QPlatformFontDatabase *m_fontDatabase;
     QPlatformNativeInterface *m_nativeInterface;
     QPlatformPrinterSupport *m_printerSupport;
+
+    QPlatformInputContext *m_inputContext;
 };
 
 QT_END_NAMESPACE
index 5c03425..adaed53 100644 (file)
 #include <X11/keysym.h>
 #include <QtGui/QWindowSystemInterface>
 #include <QtCore/QTextCodec>
+#include <private/qguiapplication_p.h>
 #include <stdio.h>
 
+#define XCB_USE_IBUS
+#if defined(XCB_USE_IBUS)
+#include "QtPlatformSupport/qibusplatforminputcontext.h"
+#endif
+
 #ifndef XK_ISO_Left_Tab
 #define XK_ISO_Left_Tab         0xFE20
 #endif
@@ -1023,6 +1029,11 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
 
     QByteArray chars;
     xcb_keysym_t sym = lookupString(window, state, code, type, &chars);
+
+    QIBusPlatformInputContext *ic = static_cast<QIBusPlatformInputContext *>(QGuiApplicationPrivate::platformIntegration()->inputContext());
+    if (ic && ic->x11FilterEvent(sym, code, state, type == QEvent::KeyPress))
+        return;
+
     Qt::KeyboardModifiers modifiers;
     int qtcode = 0;
     int count = chars.count();
index 33a7494..4b24242 100644 (file)
@@ -84,5 +84,8 @@ QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB
 
 CONFIG += qpa/genericunixfontdatabase
 
+QT += dbus
+LIBS += -ldbus-1
+
 target.path += $$[QT_INSTALL_PLUGINS]/platforms
 INSTALLS += target
index a8bd5ca..a29a265 100644 (file)
@@ -11190,7 +11190,6 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable)
 */
 void QWidget::updateMicroFocus()
 {
-#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_OS_SYMBIAN))
     Q_D(QWidget);
     // and optimization to update input context only it has already been created.
     if (d->assignedInputContext() || qApp->d_func()->inputContext) {
@@ -11198,7 +11197,6 @@ void QWidget::updateMicroFocus()
         if (ic)
             ic->update();
     }
-#endif
 #ifndef QT_NO_ACCESSIBILITY
     if (isVisible()) {
         // ##### is this correct