summaryrefslogtreecommitdiffstats
path: root/client/qt4
diff options
context:
space:
mode:
Diffstat (limited to 'client/qt4')
-rw-r--r--client/qt4/.gitignore1
-rw-r--r--client/qt4/Makefile.am55
-rw-r--r--client/qt4/ibus-client.cpp548
-rw-r--r--client/qt4/ibus-client.h87
-rw-r--r--client/qt4/ibus-input-context.cpp243
-rw-r--r--client/qt4/ibus-input-context.h69
-rw-r--r--client/qt4/ibus.pro40
-rw-r--r--client/qt4/im-ibus-qt.cpp136
8 files changed, 1179 insertions, 0 deletions
diff --git a/client/qt4/.gitignore b/client/qt4/.gitignore
new file mode 100644
index 0000000..52bae9b
--- /dev/null
+++ b/client/qt4/.gitignore
@@ -0,0 +1 @@
+moc*.cpp
diff --git a/client/qt4/Makefile.am b/client/qt4/Makefile.am
new file mode 100644
index 0000000..012a6b0
--- /dev/null
+++ b/client/qt4/Makefile.am
@@ -0,0 +1,55 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+
+EXTRA_DIST = \
+ ibus-client.cpp \
+ ibus-client.h \
+ ibus-input-context.cpp \
+ ibus-input-context.h \
+ ibus.pro \
+ im-ibus-qt.cpp \
+ $(NULL)
+
+if IBUS_BUILD_QT4
+Makefile.qmake: ibus.pro
+ $(QMAKE) -makefile -o Makefile.qmake $(srcdir)/ibus.pro
+
+all-local: Makefile.qmake
+ $(MAKE) -f Makefile.qmake $(AM_MAKEFLAGS) all
+
+check-local: Makefile.qmake
+
+clean-local: Makefile.qmake
+ $(MAKE) -f Makefile.qmake $(AM_MAKEFLAGS) clean
+
+distclean-local: Makefile.qmake
+ $(MAKE) -f Makefile.qmake $(AM_MAKEFLAGS) distclean
+
+install-exec-local: Makefile.qmake
+ $(MAKE) -f Makefile.qmake $(AM_MAKEFLAGS) INSTALL_ROOT=$(DESTDIR) install
+
+uninstall-local: Makefile.qmake
+ $(MAKE) -f Makefile.qmake $(AM_MAKEFLAGS) INSTALL_ROOT=$(DESTDIR) uninstall
+
+test: all
+ QT_IM_MODULE=ibus kwrite
+endif
+
diff --git a/client/qt4/ibus-client.cpp b/client/qt4/ibus-client.cpp
new file mode 100644
index 0000000..cb37b1b
--- /dev/null
+++ b/client/qt4/ibus-client.cpp
@@ -0,0 +1,548 @@
+/* vim:set noet ts=4: */
+/*
+ * ibus - The Input Bus
+ *
+ * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+#include <QtDebug>
+#include <QFile>
+#include <QDBusConnection>
+#include <QCoreApplication>
+#include <QDBusMessage>
+#include <QDBusArgument>
+
+#include "ibus-client.h"
+#include "ibus-input-context.h"
+
+#ifdef Q_WS_X11
+# include <QX11Info>
+# include <X11/Xlib.h>
+# include <X11/keysym.h>
+# include <X11/Xutil.h>
+#endif
+
+#define IBUS_NAME "org.freedesktop.IBus"
+#define IBUS_PATH "/org/freedesktop/IBus"
+#define IBUS_INTERFACE "org.freedesktop.IBus"
+
+
+IBusClient::IBusClient ()
+ : ibus (NULL), focused_context (NULL)
+{
+ username = getlogin ();
+ if (username.isNull ())
+ username = getenv ("LOGNAME");
+ if (username.isNull ())
+ username = getenv ("USER");
+ if (username.isNull ())
+ username = getenv ("LNAME");
+ if (username.isNull ())
+ username = getenv ("USERNAME");
+
+ session = getenv ("DISPLAY");
+ session.replace (":", "-");
+
+ ibus_addr = QString("unix:path=/tmp/ibus-%1/ibus-%2").arg (username, session);
+ connectToBus ();
+
+ QObject::connect (
+ &watcher,
+ SIGNAL(directoryChanged(const QString &)),
+ this,
+ SLOT(slotDirectoryChanged(const QString &)));
+
+ QString ibus_dir;
+
+ ibus_dir = QString ("/tmp/ibus-%1/").arg (username);
+ watcher.addPath (ibus_dir);
+}
+
+IBusClient::~IBusClient ()
+{
+ if (ibus)
+ delete ibus;
+}
+
+QString
+IBusClient::createInputContextRemote ()
+{
+ QString ic;
+ if (ibus) {
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "CreateInputContext");
+ message << QCoreApplication::applicationName ();
+ message = ibus->call (message);
+
+ if (message.type () == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+ else if (message.type () == QDBusMessage::ReplyMessage) {
+ ic = message.arguments () [0].toString ();
+ }
+ }
+ return ic;
+}
+
+QInputContext *
+IBusClient::createInputContext ()
+{
+ IBusInputContext *ctx;
+ QString ic;
+
+ ic = createInputContextRemote ();
+
+ ctx = new IBusInputContext (0, this, ic);
+ context_list.append (ctx);
+
+ if (! ic.isEmpty ()) {
+ context_dict[ic] = ctx;
+ }
+
+ return (QInputContext *) ctx;
+}
+
+void
+IBusClient::releaseInputContext (IBusInputContext *ctx)
+{
+ Q_ASSERT (ctx);
+
+ QString ic = ctx->getIC ();
+
+ if (ibus && !ic.isEmpty ()) {
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "ReleaseInputContext");
+ message << ctx->getIC ();
+ message = ibus->call (message);
+
+ if (message.type () == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+ context_dict.remove (ic);
+ }
+ context_list.removeAll (ctx);
+}
+
+#ifndef Q_WS_X11
+static void
+translate_key_event (const QKeyEvent *event, quint32 *keyval, bool *is_press, quint32 *state)
+{
+ Q_ASSERT (event);
+ Q_ASSERT (keyval);
+ Q_ASSERT (is_press);
+ Q_ASSERT (state);
+
+ *keyval = event->key ();
+ *is_press = (event->type() == QEvent::KeyPress);
+
+ Qt::KeyboardModifiers modifiers = event->modifiers ();
+ *state = 0;
+ if (modifiers & Qt::ShiftModifier) {
+ *state |= (1<< 0);
+ }
+ if (modifiers & Qt::ControlModifier) {
+ *state |= (1<< 2);
+ }
+ if (modifiers & Qt::AltModifier) {
+ *state |= (1<< 3);
+ }
+ if (modifiers & Qt::MetaModifier) {
+ *state |= (1<< 28);
+ }
+ if (modifiers & Qt::KeypadModifier) {
+ // *state |= (1<< 28);
+ }
+ if (modifiers & Qt::GroupSwitchModifier) {
+ // *state |= (1<< 28);
+ }
+}
+
+bool
+IBusClient::filterEvent (IBusInputContext *ctx, QEvent *event)
+{
+ return true;
+}
+#endif
+
+#ifdef Q_WS_X11
+static inline bool
+translate_x_key_event (XEvent *xevent, quint32 *keyval, bool *is_press, quint32 *state)
+{
+ Q_ASSERT (xevent);
+ Q_ASSERT (keyval);
+ Q_ASSERT (state);
+ Q_ASSERT (is_press);
+
+ if (xevent->type != KeyPress && xevent->type != KeyRelease)
+ return false;
+
+ *is_press = (xevent->type == KeyPress);
+ *state = xevent->xkey.state;
+
+ char key_str[64];
+
+ if (XLookupString (&xevent->xkey, key_str, sizeof (key_str), (KeySym *)keyval, 0) <= 0) {
+ *keyval = (quint32) XLookupKeysym (&xevent->xkey, 0);
+ }
+
+ return true;
+
+}
+
+bool
+IBusClient::x11FilterEvent (IBusInputContext *ctx, QWidget * /* keywidget */, XEvent *xevent)
+{
+ Q_ASSERT (ctx);
+ Q_ASSERT (keywidget);
+ Q_ASSERT (xevent);
+
+ quint32 keyval;
+ quint32 state;
+ bool is_press;
+
+ if (focused_context != ctx) {
+ focusIn (ctx);
+ }
+
+ if (ibus == NULL || !ibus->isConnected () || ctx->getIC().isEmpty ())
+ return false;
+
+ if (!translate_x_key_event (xevent, &keyval, &is_press, &state))
+ return false;
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "ProcessKeyEvent");
+ message << ctx->getIC ();
+ message << keyval;
+ message << is_press;
+ message << state;
+
+ message = ibus->call (message);
+
+ if (message.type() == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ return false;
+ }
+ else
+ return message.arguments ()[0].toBool ();
+}
+#endif
+
+void
+IBusClient::mouseHandler (IBusInputContext * /*ctx */, int /* x */, QMouseEvent * /* event */)
+{
+ return;
+}
+
+void
+IBusClient::setCursorLocation (IBusInputContext *ctx, QRect &rect)
+{
+ Q_ASSERT (ctx);
+
+ if (focused_context != ctx) {
+ focusIn (ctx);
+ }
+
+ if (ibus == NULL || !ibus->isConnected () || ctx->getIC().isEmpty ())
+ return;
+
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "SetCursorLocation");
+ message << ctx->getIC ();
+ message << rect.x ();
+ message << rect.y ();
+ message << rect.width ();
+ message << rect.height ();
+ message = ibus->call (message);
+ if (message.type() == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+}
+
+void
+IBusClient::reset (IBusInputContext *ctx)
+{
+ Q_ASSERT (ctx);
+
+ if (ibus == NULL || !ibus->isConnected () || ctx->getIC().isEmpty ())
+ return;
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "Reset");
+ message << ctx->getIC ();
+ message = ibus->call (message);
+ if (message.type() == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+}
+
+void
+IBusClient::focusIn (IBusInputContext *ctx)
+{
+ Q_ASSERT (ctx);
+ if (focused_context != ctx && focused_context != NULL)
+ focusOut (focused_context);
+ focused_context = ctx;
+
+ if (ibus == NULL || !ibus->isConnected () || ctx->getIC().isEmpty ())
+ return;
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "FocusIn");
+ message << ctx->getIC ();
+ message = ibus->call (message);
+ if (message.type() == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+
+}
+
+void
+IBusClient::focusOut (IBusInputContext *ctx)
+{
+ Q_ASSERT (ctx);
+
+ if (focused_context != ctx)
+ return;
+
+ focused_context = NULL;
+
+ if (ibus == NULL || !ibus->isConnected () || ctx->getIC().isEmpty ())
+ return;
+
+ QDBusMessage message = QDBusMessage::createMethodCall (
+ IBUS_NAME,
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "FocusOut");
+ message << ctx->getIC ();
+ message = ibus->call (message);
+ if (message.type() == QDBusMessage::ErrorMessage) {
+ qWarning() << message.errorMessage ();
+ }
+}
+void
+IBusClient::widgetDestroyed (IBusInputContext * /* ctx */, QWidget * /* widget */)
+{
+}
+
+bool
+IBusClient::connectToBus ()
+{
+ QDBusConnection *connection = NULL;
+
+ if (ibus != NULL)
+ return false;
+
+ connection = new QDBusConnection (
+ QDBusConnection::connectToBus (
+ ibus_addr,
+ QString ("ibus")));
+
+ if (!connection->isConnected ()) {
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ if (!connection->connect ("",
+ "",
+ "org.freedesktop.DBus.Local",
+ "Disconnected",
+ this, SLOT (slotIBusDisconnected()))) {
+ qWarning () << "Can not connect Disconnected signal";
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ if (!connection->connect ("",
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "CommitString",
+ this, SLOT (slotCommitString(QString, QString)))) {
+ qWarning () << "Can not connect CommitString signal";
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ if (!connection->connect ("",
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "UpdatePreedit",
+ this, SLOT (slotUpdatePreedit(QDBusMessage)))) {
+ qWarning () << "Can not connect UpdatePreedit signal";
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ if (!connection->connect ("",
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "ShowPreedit",
+ this, SLOT (slotShowPreedit(QDBusMessage)))) {
+ qWarning () << "Can not connect ShowPreedit signal";
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ if (!connection->connect ("",
+ IBUS_PATH,
+ IBUS_INTERFACE,
+ "HidePreedit",
+ this, SLOT (slotHidePreedit(QDBusMessage)))) {
+ qWarning () << "Can not connect ShowPreedit signal";
+ delete connection;
+ QDBusConnection::disconnectFromBus ("ibus");
+ return false;
+ }
+
+ ibus = connection;
+
+ QList <IBusInputContext *>::iterator i;
+ for (i = context_list.begin (); i != context_list.end (); ++i ) {
+ QString ic = createInputContextRemote ();
+ (*i)->setIC (ic);
+ context_dict[ic] = *i;
+ }
+
+ return true;
+}
+
+void
+IBusClient::disconnectFromBus ()
+{
+ if (ibus) {
+ delete ibus;
+ ibus = NULL;
+ QDBusConnection::disconnectFromBus ("ibus");
+ QList <IBusInputContext *>::iterator i;
+ for (i = context_list.begin (); i != context_list.end (); ++i ) {
+ (*i)->setIC ("");
+ }
+ context_dict.clear ();
+ }
+}
+
+void
+IBusClient::slotDirectoryChanged (const QString & /*path*/)
+{
+ if (ibus && !ibus->isConnected ())
+ disconnectFromBus ();
+
+ if (ibus == NULL ) {
+ if (QFile::exists (ibus_addr)) {
+ usleep (500);
+ connectToBus ();
+ }
+ }
+}
+
+void
+IBusClient::slotIBusDisconnected ()
+{
+ disconnectFromBus ();
+}
+
+
+void
+IBusClient::slotCommitString (QString ic, QString text)
+{
+ IBusInputContext *ctx = context_dict[ic];
+ ctx->commitString (text);
+}
+
+void
+IBusClient::slotUpdatePreedit (QDBusMessage message)
+{
+ QString ic;
+ QString text;
+ QVariant attrs;
+ int cursor_pos;
+ bool visible;
+
+ QList<QVariant> args = message.arguments ();
+
+ ic = args[0].toString ();
+ text = args[1].toString ();
+ attrs = args[2];
+ cursor_pos = args[3].toInt ();
+ visible = args[4].toBool ();
+ QList <QList <quint32> > attr_list;
+ const QDBusArgument arg = attrs.value <QDBusArgument> ();
+ arg.beginArray ();
+ while ( !arg.atEnd ()) {
+ quint32 type, value, start_index, end_index;
+
+ arg.beginArray ();
+ arg >> type >> value >> start_index >> end_index;
+ arg.endArray ();
+ QList <quint32> attr;
+ attr.append (type);
+ attr.append (value);
+ attr.append (start_index);
+ attr.append (end_index);
+ attr_list.append (attr);
+ }
+ arg.endArray ();
+
+ IBusInputContext *ctx = context_dict[ic];
+ ctx->updatePreedit (text, attr_list, cursor_pos, visible);
+}
+
+void
+IBusClient::slotShowPreedit (QDBusMessage message)
+{
+ QString ic;
+
+ QList<QVariant> args = message.arguments ();
+
+ ic = args[0].toString ();
+ IBusInputContext *ctx = context_dict[ic];
+ ctx->showPreedit ();
+}
+
+void
+IBusClient::slotHidePreedit (QDBusMessage message)
+{
+ QString ic;
+
+ QList<QVariant> args = message.arguments ();
+
+ ic = args[0].toString ();
+ IBusInputContext *ctx = context_dict[ic];
+ ctx->hidePreedit ();
+}
+
diff --git a/client/qt4/ibus-client.h b/client/qt4/ibus-client.h
new file mode 100644
index 0000000..285d633
--- /dev/null
+++ b/client/qt4/ibus-client.h
@@ -0,0 +1,87 @@
+/* vim:set noet ts=4: */
+/*
+ * ibus - The Input Bus
+ *
+ * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+#ifndef __IBUS_CLIENT_H_
+#define __IBUS_CLIENT_H_
+#include <QObject>
+#include <QList>
+#include <QHash>
+#include <QInputContext>
+#include <QFileSystemWatcher>
+#include <QDBusMessage>
+
+class QDBusConnection;
+class IBusInputContext;
+
+class IBusClient : public QObject {
+ Q_OBJECT
+public:
+ IBusClient ();
+ ~IBusClient ();
+
+public:
+
+#ifndef Q_WS_X11
+ bool filterEvent (IBusInputContext *ctx, const QEvent *event);
+#endif
+
+ bool isComposing (IBusInputContext const *ctx);
+ void mouseHandler (IBusInputContext *ctx, int x, QMouseEvent *event);
+ void widgetDestroyed (IBusInputContext *ctx, QWidget *widget);
+
+#ifdef Q_WS_X11
+ bool x11FilterEvent (IBusInputContext *ctx, QWidget *keywidget, XEvent *xevent);
+#endif
+
+public:
+ QInputContext *createInputContext ();
+ void releaseInputContext (IBusInputContext *ctx);
+ void setCursorLocation (IBusInputContext *ctx, QRect &rect);
+ void focusIn (IBusInputContext *ctx);
+ void focusOut (IBusInputContext *ctx);
+ void reset (IBusInputContext *ctx);
+
+private slots:
+ void slotDirectoryChanged (const QString &path);
+ void slotFileChanged (const QString &path);
+ void slotIBusDisconnected ();
+ void slotCommitString (QString ic, QString text);
+ //void slotUpdatePreedit (QString ic, QString text, QVariant attrs, int cursor_pos, bool show);
+ void slotUpdatePreedit (QDBusMessage message);
+ void slotShowPreedit (QDBusMessage message);
+ void slotHidePreedit (QDBusMessage message);
+
+private:
+ bool connectToBus ();
+ void disconnectFromBus ();
+ QString createInputContextRemote ();
+
+ QDBusConnection *ibus;
+ QFileSystemWatcher watcher;
+ QList <IBusInputContext *> context_list;
+ QHash <QString, IBusInputContext *>context_dict;
+ IBusInputContext *focused_context;
+ QString username;
+ QString session;
+ QString ibus_addr;
+};
+
+#endif // __IBUS_CLIENT_H_
diff --git a/client/qt4/ibus-input-context.cpp b/client/qt4/ibus-input-context.cpp
new file mode 100644
index 0000000..692fecb
--- /dev/null
+++ b/client/qt4/ibus-input-context.cpp
@@ -0,0 +1,243 @@
+/* vim:set noet ts=4: */
+/*
+ * ibus - The Input Bus
+ *
+ * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+#include "ibus-input-context.h"
+#include "ibus-client.h"
+#include <QtDebug>
+#include <QInputMethodEvent>
+#include <QTextCharFormat>
+
+typedef QInputMethodEvent::Attribute QAttribute;
+
+IBusInputContext::IBusInputContext (QObject *parent, IBusClient *client, QString &ic)
+ : QInputContext (parent), client (client), ic (ic), preedit_visible (false)
+{
+}
+
+IBusInputContext::~IBusInputContext ()
+{
+ client->releaseInputContext (this);
+}
+
+bool
+IBusInputContext::filterEvent (const QEvent *event)
+{
+#ifndef Q_WS_X11
+ if (client->filterEvent (this, event))
+ return true;
+ return QInputContext::filterEvent (event);
+#else
+ return QInputContext::filterEvent (event);
+#endif
+}
+
+QFont
+IBusInputContext::font () const
+{
+ return QInputContext::font ();
+}
+
+QString
+IBusInputContext::identifierName ()
+{
+ return QString ("ibus");
+}
+
+QString
+IBusInputContext::language()
+{
+ return QString ("");
+}
+
+void
+IBusInputContext::mouseHandler (int x, QMouseEvent *event)
+{
+ client->mouseHandler (this, x, event);
+ QInputContext::mouseHandler (x, event);
+}
+
+void
+IBusInputContext::reset()
+{
+ client->reset (this);
+}
+
+void
+IBusInputContext::update ()
+{
+ QWidget *widget;
+
+ if ((widget = focusWidget ()) == NULL)
+ return;
+
+ QRect rect = widget->inputMethodQuery(Qt::ImMicroFocus).toRect ();
+
+#if 0
+ QFont font = widget->inputMethodQuery(Qt::ImFont).value <QFont> ();
+ qDebug () << rect << preedit_string << preedit_cursor_pos;
+
+ QFontMetrics fm(font);
+ int textWidth = fm.width (preedit_string.left (preedit_cursor_pos));
+ rect.translate (textWidth, 0);
+#endif
+
+ QPoint topleft = widget->mapToGlobal(QPoint(0,0));
+ rect.translate (topleft);
+ if (cursor_location != rect ) {
+ client->setCursorLocation (this, rect);
+ cursor_location = rect;
+ }
+
+#if 0
+ QVariant value;
+ value = widget->inputMethodQuery(Qt::ImMicroFocus);
+ qDebug () << value;
+ value = widget->inputMethodQuery(Qt::ImFont);
+ qDebug () << value;
+ value = widget->inputMethodQuery(Qt::ImCursorPosition);
+ qDebug () << value;
+ value = widget->inputMethodQuery(Qt::ImSurroundingText);
+ qDebug () << value;
+ value = widget->inputMethodQuery(Qt::ImCurrentSelection);
+ qDebug () << value;
+#endif
+}
+
+bool
+IBusInputContext::isComposing() const
+{
+ return (!preedit_string.isEmpty ()) && preedit_visible;
+}
+
+void
+IBusInputContext::setFocusWidget (QWidget *widget)
+{
+ // qDebug () << "setFocusWidget (" << widget << ")";
+ QInputContext::setFocusWidget (widget);
+ update ();
+}
+
+void
+IBusInputContext::widgetDestroyed (QWidget *widget)
+{
+ QInputContext::widgetDestroyed (widget);
+ update ();
+}
+
+#ifdef Q_WS_X11
+bool
+IBusInputContext::x11FilterEvent (QWidget *keywidget, XEvent *xevent)
+{
+ if (client->x11FilterEvent (this, keywidget, xevent))
+ return true;
+ return QInputContext::x11FilterEvent (keywidget, xevent);
+}
+#endif
+
+void
+IBusInputContext::setIC (QString ic)
+{
+ this->ic = ic;
+}
+
+QString
+IBusInputContext::getIC ()
+{
+ return ic;
+}
+
+void
+IBusInputContext::commitString (QString text)
+{
+ QInputMethodEvent event;
+ event.setCommitString (text);
+ sendEvent (event);
+ update ();
+}
+
+void
+IBusInputContext::updatePreedit (QString text, QList <QList <quint32> > attr_list, int cursor_pos, bool visible)
+{
+ // qDebug () << text << cursor_pos << show;
+ QList <QAttribute> qattrs;
+
+ if (visible) {
+ // append cursor pos
+ qattrs.append (QAttribute (QInputMethodEvent::Cursor, cursor_pos, true, 0));
+
+ // append attributes
+ for (QList <QList <quint32> >::iterator it = attr_list.begin (); it != attr_list.end(); ++ it) {
+
+ QList <quint32> attr = *it;
+ QTextCharFormat format;
+
+ switch (attr[0]) {
+ case 1: // underline
+ format.setUnderlineStyle (QTextCharFormat::SingleUnderline);
+ break;
+ case 2: // foreground
+ format.setForeground (QBrush (QColor (attr[1])));
+ break;
+ case 3: // background
+ format.setBackground (QBrush (QColor (attr[1])));
+ break;
+ default:
+ break;
+ }
+
+ qattrs.append (QAttribute (QInputMethodEvent::TextFormat, attr[2], attr[3] - attr[2], QVariant (format)));
+ // qDebug () << attr[0] << attr[2] << attr[3] - attr[2];
+ }
+ }
+ else {
+ qattrs.append (QAttribute (QInputMethodEvent::Cursor, 0, true, 0));
+ text = "";
+ cursor_pos = 0;
+ }
+
+ preedit_string = text;
+ preedit_visible = visible;
+ preedit_attrs = attr_list;
+ preedit_cursor_pos = cursor_pos;
+
+ QInputMethodEvent event (text, qattrs);
+ sendEvent (event);
+ update ();
+}
+
+void
+IBusInputContext::showPreedit ()
+{
+ if (preedit_visible)
+ return;
+
+ updatePreedit (preedit_string, preedit_attrs, preedit_cursor_pos, TRUE);
+}
+
+void
+IBusInputContext::hidePreedit ()
+{
+ if (!preedit_visible)
+ return;
+
+ updatePreedit (preedit_string, preedit_attrs, preedit_cursor_pos, FALSE);
+}
+
diff --git a/client/qt4/ibus-input-context.h b/client/qt4/ibus-input-context.h
new file mode 100644
index 0000000..317c876
--- /dev/null
+++ b/client/qt4/ibus-input-context.h
@@ -0,0 +1,69 @@
+/* vim:set noet ts=4: */
+/*
+ * ibus - The Input Bus
+ *
+ * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+#ifndef __IBUS_INPUT_CONTEXT_H_
+#define __IBUS_INPUT_CONTEXT_H_
+#include <QInputContext>
+#include <QList>
+#include "ibus-client.h"
+
+class IBusClient;
+
+class IBusInputContext : public QInputContext {
+ Q_OBJECT
+public:
+ IBusInputContext (QObject *parent, IBusClient *client, QString &ic);
+ ~IBusInputContext ();
+
+public:
+ bool filterEvent (const QEvent *event);
+ QFont font () const;
+ QString identifierName ();
+ bool isComposing() const;
+ QString language();
+ void mouseHandler (int x, QMouseEvent *event);
+ void reset();
+ void update ();
+ void setFocusWidget (QWidget *widget );
+ void widgetDestroyed (QWidget *widget);
+#ifdef Q_WS_X11
+ bool x11FilterEvent (QWidget *keywidget, XEvent *event);
+#endif
+ void setIC (QString ic);
+ QString getIC ();
+
+ void commitString (QString text);
+ void updatePreedit (QString text, QList <QList <quint32> > attr_list, int cursor_pos, bool visible);
+ void showPreedit ();
+ void hidePreedit ();
+
+
+private:
+ IBusClient *client;
+ QString ic;
+ QString preedit_string;
+ bool preedit_visible;
+ int preedit_cursor_pos;
+ QList <QList <quint32> > preedit_attrs;
+ QRect cursor_location;
+};
+
+#endif //__IBUS_INPUT_CONTEXT_H_
diff --git a/client/qt4/ibus.pro b/client/qt4/ibus.pro
new file mode 100644
index 0000000..1c308a2
--- /dev/null
+++ b/client/qt4/ibus.pro
@@ -0,0 +1,40 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+
+TEMPLATE = lib
+TARGET = ibus
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG += qt qdbus plugin
+
+# Input
+HEADERS += \
+ ibus-client.h \
+ ibus-input-context.h
+
+SOURCES += \
+ ibus-client.cpp \
+ ibus-input-context.cpp \
+ im-ibus-qt.cpp
+
+target.path += $$[QT_INSTALL_PLUGINS]/inputmethods
+INSTALLS += target
diff --git a/client/qt4/im-ibus-qt.cpp b/client/qt4/im-ibus-qt.cpp
new file mode 100644
index 0000000..0d6944b
--- /dev/null
+++ b/client/qt4/im-ibus-qt.cpp
@@ -0,0 +1,136 @@
+/* vim:set noet ts=4: */
+/*
+ * ibus - The Input Bus
+ *
+ * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+#include <cassert>
+#include <Qt>
+#include <QInputContextPlugin>
+#include "ibus-client.h"
+
+using namespace Qt;
+
+#define IBUS_IDENTIFIER_NAME "ibus"
+
+static IBusClient *client;
+
+/* The class Definition */
+class IBusInputContextPlugin: public QInputContextPlugin
+{
+
+ private:
+
+ /**
+ * The language list for SCIM.
+ */
+ static QStringList ibus_languages;
+
+ public:
+
+ IBusInputContextPlugin (QObject *parent = 0);
+
+ ~IBusInputContextPlugin ();
+
+ QStringList keys () const;
+
+ QStringList languages (const QString &key);
+
+ QString description (const QString &key);
+
+ QInputContext *create (const QString &key);
+
+ QString displayName (const QString &key);
+
+};
+
+
+/* Implementations */
+QStringList IBusInputContextPlugin::ibus_languages;
+
+
+IBusInputContextPlugin::IBusInputContextPlugin (QObject *parent)
+ :QInputContextPlugin (parent)
+{
+}
+
+
+IBusInputContextPlugin::~IBusInputContextPlugin ()
+{
+ if (client != NULL) {
+ delete client;
+ client = NULL;
+ }
+}
+
+QStringList
+IBusInputContextPlugin::keys () const
+{
+ QStringList identifiers;
+ identifiers.push_back (IBUS_IDENTIFIER_NAME);
+ return identifiers;
+}
+
+
+QStringList
+IBusInputContextPlugin::languages (const QString & key)
+{
+ if (key.toLower () != IBUS_IDENTIFIER_NAME)
+ return QStringList ();
+
+ if (ibus_languages.empty ()) {
+ ibus_languages.push_back ("zh_CN");
+ ibus_languages.push_back ("zh_TW");
+ ibus_languages.push_back ("zh_HK");
+ ibus_languages.push_back ("ja");
+ ibus_languages.push_back ("ko");
+ }
+ return ibus_languages;
+}
+
+
+QString
+IBusInputContextPlugin::description (const QString &key)
+{
+ if (key.toLower () != IBUS_IDENTIFIER_NAME)
+ return QString ("");
+
+ return QString::fromUtf8 ("Qt immodule plugin for IBus");
+}
+
+
+QInputContext *
+IBusInputContextPlugin::create (const QString &key)
+{
+ if (key.toLower () != IBUS_IDENTIFIER_NAME) {
+ return NULL;
+ } else {
+ if (client == NULL) {
+ client = new IBusClient ();
+ }
+ return client->createInputContext ();
+ }
+}
+
+
+QString IBusInputContextPlugin::displayName (const QString &key)
+{
+ return key;
+}
+
+Q_EXPORT_PLUGIN2 (IBusInputContextPlugin, IBusInputContextPlugin)