From 60c84bbf51db184bfe01e35b0948edf6f49b2e76 Mon Sep 17 00:00:00 2001
From: Zankio <xxoojoeooxx1@gmail.com>
Date: Sat, 3 Jun 2017 02:52:58 +0800
Subject: [PATCH] Add hime inputcontext plugin for linux version

(#3129)

Signed-off-by: Zankio <xxoojoeooxx1@gmail.com>
(github: zankio)
---
 Telegram/Patches/qtbase_5_6_2.diff         | 22414 ++++++++++++++++++-
 Telegram/SourceFiles/qt_static_plugins.cpp |     1 +
 Telegram/gyp/telegram_linux.gypi           |     1 +
 3 files changed, 22413 insertions(+), 3 deletions(-)

diff --git a/Telegram/Patches/qtbase_5_6_2.diff b/Telegram/Patches/qtbase_5_6_2.diff
index 236a4dbf2..a5dfb9017 100644
--- a/Telegram/Patches/qtbase_5_6_2.diff
+++ b/Telegram/Patches/qtbase_5_6_2.diff
@@ -11252,8 +11252,22416 @@ index 0000000..f0c9202
 +#endif
 +
 +#endif /* _XKBCOMMON_H_ */
+diff --git a/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.cpp b/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.cpp
+new file mode 100644
+index 0000000..0ffc6f4
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.cpp
+@@ -0,0 +1,341 @@
++#include <QtGui/QKeyEvent>
++#include <QtGui/QGuiApplication>
++#include <QtGui/QInputMethod>
++#include <QtGui/QTextCharFormat>
++#include <QtGui/QPalette>
++#include <QtGui/QWindow>
++
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++
++// confliction of qt & x11
++typedef unsigned int KeySym;
++struct Display;
++typedef unsigned int Window;
++typedef struct {
++    short x, y;
++} XPoint;
++
++#include "include/util.h"
++#include "include/im-client/hime-im-client.h"
++#include "hime-imcontext-qt.h"
++
++static WId focused_win;
++
++#include <QtGui/qpa/qplatformnativeinterface.h>
++
++#if DEBUG
++FILE *out_fp;
++void __hime_dbg_(const char *fmt,...)
++{
++    va_list args;
++
++    if (!out_fp) {
++#if 0
++        out_fp = fopen("/tmp/a.txt", "w");
++#else
++        out_fp = stdout;
++#endif
++    }
++
++    va_start(args, fmt);
++    vfprintf(out_fp, fmt, args);
++    fflush(out_fp);
++    va_end(args);
++}
++#endif
++
++QHimePlatformInputContext::QHimePlatformInputContext()
++{
++    dbg("QHimePlatformInputContext::QHimePlatformInputContext() \n");
++    QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
++    if(!native)
++        return;
++    Display *display = static_cast<Display *>(native->nativeResourceForWindow("display", NULL));
++
++    if (!(hime_ch = hime_im_client_open(display))) {
++        perror("cannot open hime_ch");
++        dbg("hime_im_client_open error\n");
++        return;
++    }
++
++    dbg("QHimePlatformInputContext succ\n");
++}
++
++QHimePlatformInputContext::~QHimePlatformInputContext()
++{
++    if (hime_ch==NULL)
++        return;
++      hime_im_client_close(hime_ch);
++    hime_ch = NULL;
++}
++
++
++bool QHimePlatformInputContext::isValid() const
++{
++    dbg("QHimePlatformInputContext::isValid()\n");
++    return true;
++}
++
++void QHimePlatformInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
++{
++    dbg("QHimePlatformInputContext::invokeAction(n");
++    // FIXME nop? remove me
++}
++
++void QHimePlatformInputContext::commitPreedit()
++{
++    dbg("QHimePlatformInputContext::commitPreedit\n");
++    // use this to flush
++    int preedit_cursor_position=0;
++    int sub_comp_len;
++    char *str=NULL;
++    HIME_PREEDIT_ATTR att[HIME_PREEDIT_ATTR_MAX_N];
++    hime_im_client_get_preedit(hime_ch, &str, att, &preedit_cursor_position, &sub_comp_len);
++    if (str) {
++        if (strlen(str) > 0) {
++            dbg("send enter to flush\n");
++            send_key_press(0xff0d, 0); // Enter
++        } else {
++            dbg("empty string\n");
++        }
++
++        free(str);
++        update_preedit();
++    } else {
++        dbg("no str\n");
++    }
++}
++
++
++void QHimePlatformInputContext::reset()
++{
++    dbg("QHimePlatformInputContext::reset()\n");
++    if (hime_ch) {
++        hime_im_client_reset(hime_ch);
++        update_preedit();
++    }
++}
++
++void QHimePlatformInputContext::update(Qt::InputMethodQueries queries )
++{
++    dbg("QHimePlatformInputContext::update\n");
++    QObject *input = qApp->focusObject();
++    if (!input)
++        return;
++
++    QInputMethodQueryEvent query(queries);
++    QGuiApplication::sendEvent(input, &query);
++
++    if (queries & Qt::ImCursorRectangle) {
++        cursorMoved();
++    }
++}
++
++// this one is essential
++void QHimePlatformInputContext::commit()
++{
++    dbg("QHimePlatformInputContext::commit()\n");
++    commitPreedit();
++}
++
++
++void QHimePlatformInputContext::setFocusObject(QObject* object)
++{
++    dbg("QHimePlatformInputContext::setFocusObject\n");
++    QWindow *window = qApp->focusWindow();
++    if (!window) {
++        dbg("no window, focus out\n");
++        focused_win = 0;
++        char *rstr = NULL;
++        hime_im_client_focus_out2(hime_ch, &rstr);
++        if (rstr) {
++            send_str(rstr);
++        } else {
++            dbg("no str in preedit\n");
++        }
++        return;
++    }
++
++    WId win = window->winId();
++
++    if (focused_win && win != focused_win) {
++        if (hime_ch) {
++            hime_im_client_focus_out(hime_ch);
++        }
++    }
++
++    focused_win = win;
++
++    if (hime_ch) {
++        hime_im_client_set_window(hime_ch, win);
++        hime_im_client_focus_in(hime_ch);
++        cursorMoved();
++    }
++}
++
++static int last_x=-1, last_y=-1;
++
++void QHimePlatformInputContext::cursorMoved()
++{
++    dbg(" QHimePlatformInputContext::cursorMoved()\n");
++
++    QWindow *inputWindow = qApp->focusWindow();
++    if (!inputWindow)
++        return;
++
++    QRect r = qApp->inputMethod()->cursorRectangle().toRect();
++    if(!r.isValid())
++        return;
++
++    // hime server will clear the string if the cursor is moved, make sure the x,y is valid
++    int x = r.left(),  y = r.bottom();
++    if (x > inputWindow->width() || y > inputWindow->height() || x < 0 || y < 0)
++        return;
++
++    if (hime_ch && (x !=  last_x || y != last_y)) {
++        last_x = x; last_y = y;
++        dbg("move cursor %d, %d\n", x, y);
++        hime_im_client_set_cursor_location(hime_ch, x,  y);
++    }
++}
++
++
++
++void QHimePlatformInputContext::update_preedit()
++{
++    if (!hime_ch)
++        return;
++    QList<QInputMethodEvent::Attribute> attrList;
++//  QString preedit_string;
++    int preedit_cursor_position=0;
++    int sub_comp_len;
++    char *str=NULL;
++    HIME_PREEDIT_ATTR att[HIME_PREEDIT_ATTR_MAX_N];
++    int attN = hime_im_client_get_preedit(hime_ch, &str, att, &preedit_cursor_position, &sub_comp_len);
++
++    int ret;
++    hime_im_client_set_flags(hime_ch, FLAG_HIME_client_handle_use_preedit, &ret);
++
++    QObject *input = qApp->focusObject();
++
++    if (!input || !str) {
++      free(str);
++      return;
++    }
++
++
++#if DEBUG
++    dbg("update_preedit attN:%d '%s'\n", attN, str);
++#endif
++
++    int i;
++    for(i=0; i < attN; i++) {
++        int ofs0 = att[i].ofs0;
++        int len = att[i].ofs1 - att[i].ofs0;
++        QTextCharFormat format;
++
++        switch (att[i].flag) {
++            case HIME_PREEDIT_ATTR_FLAG_REVERSE:
++            {
++                QBrush brush;
++                QPalette palette;
++                palette = QGuiApplication::palette();
++                format.setBackground(QBrush(QColor(palette.color(QPalette::Active, QPalette::Highlight))));
++                format.setForeground(QBrush(QColor(palette.color(QPalette::Active, QPalette::HighlightedText))));
++            }
++            break;
++            case HIME_PREEDIT_ATTR_FLAG_UNDERLINE:
++            {
++                format.setUnderlineStyle(QTextCharFormat::DashUnderline);
++            }
++            break;
++            default:
++                ;
++        }
++
++        attrList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, ofs0,  len, format));
++    }
++
++    attrList.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,  preedit_cursor_position, 1, 0));
++
++    QInputMethodEvent im_event (QString::fromUtf8(str), attrList);
++    send_event (im_event);
++    free(str);
++}
++
++void QHimePlatformInputContext::send_event(QInputMethodEvent e) {
++    QObject *input = qApp->focusObject();
++    if (!input)
++        return;
++    QCoreApplication::sendEvent(input, &e);
++}
++
++void QHimePlatformInputContext::send_str(char *rstr) {
++    dbg("send_str %s\n",  rstr);
++    QString inputText = QString::fromUtf8(rstr);
++    free(rstr);
++    QInputMethodEvent commit_event;
++    commit_event.setCommitString (inputText);
++    send_event (commit_event);
++}
++
++bool QHimePlatformInputContext::send_key_press(quint32 keysym, quint32 state) {
++    dbg("send_key_press\n");
++    char *rstr  = NULL;
++    int result = hime_im_client_forward_key_press(hime_ch, keysym, state, &rstr);
++
++    if (rstr) {
++        send_str(rstr);
++    }
++
++    return result;
++}
++
++bool QHimePlatformInputContext::filterEvent(const QEvent* event)
++{
++    dbg("QHimePlatformInputContext::filterEvent\n");
++    if (event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease) {
++        goto ret;
++    }
++
++    const QKeyEvent* keyEvent;
++    keyEvent = static_cast<const QKeyEvent*>(event);
++    quint32 keysym ;
++    keysym = keyEvent->nativeVirtualKey();
++    quint32  state;
++    state = keyEvent->nativeModifiers();
++
++    if (!inputMethodAccepted()) {
++        goto ret;
++    }
++
++    QObject *input;
++    input = qApp->focusObject();
++
++    if (!input) {
++        goto ret;
++    }
++
++    int result;
++    if (event->type() == QEvent::KeyPress) {
++        if (send_key_press(keysym, state)) {
++            update_preedit();
++            return true;
++        }
++    } else {
++        char *rstr = NULL;
++        result = hime_im_client_forward_key_release(hime_ch,   keysym, state, &rstr);
++        if (rstr) {
++            free(rstr);
++        }
++
++        if (result) {
++            return true;
++        }
++    }
++
++ret:
++    return QPlatformInputContext::filterEvent(event);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.h b/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.h
+new file mode 100644
+index 0000000..784396f
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime-imcontext-qt.h
+@@ -0,0 +1,34 @@
++#ifndef HIME_QT5_IM_H
++#define HIME_QT5_IM_H
++
++#include <QtGui/qpa/qplatforminputcontext.h>
++
++class QInputMethodEvent;
++struct HIME_client_handle_S;
++
++class QHimePlatformInputContext : public QPlatformInputContext
++{
++    Q_OBJECT
++public:
++    QHimePlatformInputContext();
++    virtual ~QHimePlatformInputContext();
++
++    virtual bool filterEvent(const QEvent* event);
++    virtual bool isValid() const;
++    virtual void invokeAction(QInputMethod::Action , int cursorPosition);
++    virtual void reset();
++    virtual void commit();
++    virtual void update(Qt::InputMethodQueries quries );
++    virtual void setFocusObject(QObject* object);
++
++private:
++    HIME_client_handle_S *hime_ch;
++    void send_event(QInputMethodEvent e);
++    void update_preedit();
++    void cursorMoved();
++    bool send_key_press(quint32 keysym, quint32 state);
++    void commitPreedit();
++    void send_str(char *s);
++};
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/hime-qt.cpp b/src/plugins/platforminputcontexts/hime/hime-qt.cpp
+new file mode 100644
+index 0000000..c7786a8
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime-qt.cpp
+@@ -0,0 +1,24 @@
++#include <cstdio>
++
++#include "hime-qt.h"
++#include "include/util.h"
++
++#define HIMEID "hime"
++
++
++QStringList QHimePlatformInputContextPlugin::keys() const
++{
++    dbg("QStringList QHimePlatformInputContextPlugin::keys()\n");
++    return QStringList(QStringLiteral(HIMEID));
++
++}
++
++QHimePlatformInputContext *QHimePlatformInputContextPlugin::create(const QString& system, const QStringList& paramList)
++{
++    Q_UNUSED(paramList);
++    dbg("QHimePlatformInputContextPlugin::create()\n");
++
++    if (system.compare(system, QStringLiteral(HIMEID), Qt::CaseInsensitive) == 0)
++        return new QHimePlatformInputContext;
++    return 0;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/hime-qt.h b/src/plugins/platforminputcontexts/hime/hime-qt.h
+new file mode 100644
+index 0000000..0e98a17
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime-qt.h
+@@ -0,0 +1,19 @@
++#ifndef HIME_QT5_PLUGIN_H
++#define HIME_QT5_PLUGIN_H
++
++#include <QtCore/QStringList>
++#include <QtGui/qpa/qplatforminputcontextplugin_p.h>
++
++#include "hime-imcontext-qt.h"
++
++
++class QHimePlatformInputContextPlugin : public QPlatformInputContextPlugin
++{
++    Q_OBJECT
++public:
++    Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE "hime.json")
++    QStringList keys() const;
++    QHimePlatformInputContext *create(const QString& system, const QStringList& paramList);
++};
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/hime.json b/src/plugins/platforminputcontexts/hime/hime.json
+new file mode 100644
+index 0000000..f737430
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime.json
+@@ -0,0 +1,3 @@
++{
++    "Keys": [ "hime" ]
++}
+diff --git a/src/plugins/platforminputcontexts/hime/hime.pro b/src/plugins/platforminputcontexts/hime/hime.pro
+new file mode 100644
+index 0000000..cb0e098
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/hime.pro
+@@ -0,0 +1,75 @@
++TARGET = himeplatforminputcontextplugin
++
++QT += dbus gui-private
++SOURCES += $$PWD/hime-imcontext-qt.cpp \
++           $$PWD/hime-qt.cpp \
++           $$PWD/include/gtab.c \
++           $$PWD/include/pho.c \
++           $$PWD/include/tsin-parse.c \
++           $$PWD/include/im-client/hime-im-client.c \
++           $$PWD/include/im-client/hime-send.c \
++           $$PWD/include/hime-conf.c \
++           $$PWD/include/IC.c \
++           $$PWD/include/util.c \
++           $$PWD/include/gtab-buf.c \
++           $$PWD/include/im-srv.c \
++           $$PWD/include/im-addr.c \
++           $$PWD/include/hime.c \
++           $$PWD/include/hime-crypt.c \
++           $$PWD/include/lang.c \
++           $$PWD/include/win1.c \
++           $$PWD/include/tsin.c \
++           $$PWD/include/win-save-phrase.c \
++           $$PWD/include/IMdkit/lib/i18nX.c \
++           $$PWD/include/IMdkit/lib/i18nClbk.c \
++           $$PWD/include/IMdkit/lib/i18nPtHdr.c \
++           $$PWD/include/IMdkit/lib/IMConn.c \
++           $$PWD/include/IMdkit/lib/IMMethod.c \
++           $$PWD/include/IMdkit/lib/i18nIMProto.c \
++           $$PWD/include/IMdkit/lib/FrameMgr.c \
++           $$PWD/include/IMdkit/lib/i18nIc.c \
++           $$PWD/include/IMdkit/lib/i18nUtil.c \
++           $$PWD/include/IMdkit/lib/i18nMethod.c \
++           $$PWD/include/IMdkit/lib/i18nAttr.c
++
++
++HEADERS += $$PWD/hime-imcontext-qt.h \
++           $$PWD/hime-qt.h \
++           $$PWD/include/os-dep.h \
++           $$PWD/include/pho-status.h \
++           $$PWD/include/hime-gtk-compatible.h \
++           $$PWD/include/pho.h \
++           $$PWD/include/util.h \
++           $$PWD/include/im-client/hime-im-client.h \
++           $$PWD/include/im-client/hime-protocol.h \
++           $$PWD/include/im-client/hime-im-client-attr.h \
++           $$PWD/include/tsin-parse.h \
++           $$PWD/include/im-srv.h \
++           $$PWD/include/IC.h \
++           $$PWD/include/gtab.h \
++           $$PWD/include/hime-endian.h \
++           $$PWD/include/hime-conf.h \
++           $$PWD/include/lang.h \
++           $$PWD/include/hime.h \
++           $$PWD/include/win-save-phrase.h \
++           $$PWD/include/config.h \
++           $$PWD/include/gst.h \
++           $$PWD/include/gtab-buf.h \
++           $$PWD/include/IMdkit/lib/Xi18nX.h \
++           $$PWD/include/IMdkit/lib/XimFunc.h \
++           $$PWD/include/IMdkit/lib/FrameMgr.h \
++           $$PWD/include/IMdkit/include/IMdkit.h \
++           $$PWD/include/IMdkit/include/Xi18n.h \
++           $$PWD/include/IMdkit/include/XimProto.h \
++           $$PWD/include/tsin.h \
++           $$PWD/include/win1.h
++
++OTHER_FILES += $$PWD/hime.json
++
++DEFINES += HIME_VERSION=\"\\\"0.9.10\\\"\" USE_XIM HIME_TABLE_DIR=\"\\\"/usr/local/share/hime/table\\\"\" HIME_BIN_DIR=\"\\\"/usr/local/bin\\\"\"
++CONFIG += link_pkgconfig
++PKGCONFIG += glib-2.0 gtk+-2.0
++PLUGIN_TYPE = platforminputcontexts
++PLUGIN_EXTENDS = -
++PLUGIN_CLASS_NAME = QHimePlatformInputContextPlugin
++load(qt_plugin)
+diff --git a/src/plugins/platforminputcontexts/hime/include/IC.c b/src/plugins/platforminputcontexts/hime/include/IC.c
+new file mode 100644
+index 0000000..eee4d3c
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IC.c
+@@ -0,0 +1,467 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++******************************************************************/
++#include "hime.h"
++
++#undef DEBUG
++
++static IC *ic_list = (IC *)NULL;
++static IC *free_list = (IC *)NULL;
++
++void move_IC_in_win(ClientState *cs);
++
++static void free_IC_list(IC *list)
++{
++    while (list) {
++       IC *next = list->next;
++       free(list);
++       list = next;
++    }
++}
++
++void free_all_IC()
++{
++    free_IC_list(ic_list);
++    free_IC_list(free_list);
++}
++
++
++static IC
++*NewIC()
++{
++    static CARD16 icid = 0;
++    IC *rec;
++
++    if (free_list != NULL) {
++	rec = free_list;
++	free_list = free_list->next;
++    } else {
++	rec = (IC *)malloc(sizeof(IC));
++    }
++
++    bzero(rec, sizeof(IC));
++    rec->cs.input_style = InputStyleOverSpot;
++    rec->id = ++icid;
++
++    rec->next = ic_list;
++    ic_list = rec;
++    return rec;
++}
++
++IC *FindIC(CARD16 icid)
++{
++    IC *rec = ic_list;
++
++    while (rec != NULL) {
++	if (rec->id == icid)
++	  return rec;
++	rec = rec->next;
++    }
++
++    return NULL;
++}
++
++void hide_in_win(ClientState *ic);
++
++void DeleteIC(CARD16 icid)
++{
++    IC *rec, *last;
++
++    last = NULL;
++    for (rec = ic_list; rec != NULL; last = rec, rec = rec->next) {
++        if (rec->id == icid) {
++
++          if (&rec->cs == current_CS) {
++            hide_in_win(&rec->cs);
++          }
++
++          if (last != NULL)
++            last->next = rec->next;
++          else
++            ic_list = rec->next;
++
++          rec->next = free_list;
++          free_list = rec;
++          return;
++	}
++    }
++    return;
++}
++
++static int Is(char *attr, XICAttribute *attr_list) {
++	return !strcmp(attr, attr_list->name);
++}
++
++extern Window root;
++extern Display *dpy;
++
++
++void move_in_win(ClientState *cs, int x, int y);
++void show_in_win(ClientState *cs);
++extern Window focus_win;
++void save_CS_temp_to_current();
++
++void load_IC(IC *rec)
++{
++   ClientState *cs = &rec->cs;
++   Window win = cs->client_win;
++
++   if (win == focus_win && !current_CS) {
++     current_CS = cs;
++     save_CS_temp_to_current();
++   }
++
++   if (win == focus_win) {
++     if (cs->im_state == HIME_STATE_DISABLED)
++       hide_in_win(cs);
++     else
++     if (cs->im_state != HIME_STATE_DISABLED)
++       show_in_win(cs);
++   }
++
++   if (cs->input_style & InputStyleOnSpot) {
++     if (cs->im_state != HIME_STATE_DISABLED)
++       move_IC_in_win(cs);
++   } else
++   if (cs->input_style & InputStyleOverSpot) {
++     if (cs->im_state != HIME_STATE_DISABLED)
++       move_IC_in_win(cs);
++   } else
++   if (cs->input_style & InputStyleRoot) {
++     move_IC_in_win(cs);
++   }
++}
++
++
++static void
++StoreIC(IC *rec, IMChangeICStruct *call_data)
++{
++        ClientState *cs = &rec->cs;
++	XICAttribute *ic_attr = call_data->ic_attr;
++	XICAttribute *pre_attr = call_data->preedit_attr;
++	XICAttribute *sts_attr = call_data->status_attr;
++	register int i;
++
++	if (!current_CS) {
++          current_CS = cs;
++          save_CS_temp_to_current();
++        }
++#if DEBUG && 0
++        dbg(".... StoreIC\n");
++#endif
++	for (i = 0; i < (int)call_data->ic_attr_num; i++, ic_attr++) {
++		if (Is (XNInputStyle, ic_attr)) {
++                    INT32 input_style = *(INT32*)ic_attr->value;
++
++                    if (input_style & XIMPreeditCallbacks) {
++                      cs->input_style = InputStyleOnSpot;
++                    } else
++                    if (input_style & XIMPreeditPosition) {
++                      cs->input_style = InputStyleOverSpot;
++                    } else
++                    if (input_style & XIMPreeditNothing) {
++                        cs->input_style = InputStyleRoot;
++                    }
++		}
++
++		else if (Is (XNClientWindow, ic_attr)) {
++                    rec->cs.client_win = *(Window*)ic_attr->value;
++#if DEBUG
++		    dbg("rec->client_win %x\n", cs->client_win);
++#endif
++		}
++		else if (Is (XNFocusWindow, ic_attr)) {
++                    rec->focus_win = *(Window*)ic_attr->value;
++                }
++		else
++		    fprintf(stderr, "Unknown attr: %s a\n", ic_attr->name);
++	}
++
++	for (i = 0; i < (int)call_data->preedit_attr_num; i++, pre_attr++) {
++		if (Is (XNArea, pre_attr)) {
++                    rec->pre_attr.area = *(XRectangle*)pre_attr->value;
++#if DEBUG
++                   dbg("pre_attr->value: %d %d\n", rec->pre_attr.area.x, rec->pre_attr.area.y);
++#endif
++                }
++		else if (Is (XNAreaNeeded, pre_attr))
++		    rec->pre_attr.area_needed = *(XRectangle*)pre_attr->value;
++
++		else if (Is (XNSpotLocation, pre_attr)) {
++                    cs->spot_location = *(XPoint*)pre_attr->value;
++                    move_IC_in_win(cs);
++                }
++		else if (Is (XNColormap, pre_attr))
++		    rec->pre_attr.cmap = *(Colormap*)pre_attr->value;
++
++		else if (Is (XNStdColormap, pre_attr))
++		    rec->pre_attr.cmap = *(Colormap*)pre_attr->value;
++
++		else if (Is (XNForeground, pre_attr))
++		    rec->pre_attr.foreground = *(CARD32*)pre_attr->value;
++
++		else if (Is (XNBackground, pre_attr))
++		    rec->pre_attr.background = *(CARD32*)pre_attr->value;
++
++		else if (Is (XNBackgroundPixmap, pre_attr))
++		    rec->pre_attr.bg_pixmap = *(Pixmap*)pre_attr->value;
++
++		else if (Is (XNFontSet, pre_attr)) {
++			int str_length = strlen((char *)pre_attr->value);
++
++			if (rec->pre_attr.base_font != NULL) {
++				if (Is (rec->pre_attr.base_font, pre_attr))
++					continue;
++				XFree(rec->pre_attr.base_font);
++			}
++			rec->pre_attr.base_font = (char *)malloc(str_length + 1);
++			strcpy(rec->pre_attr.base_font, (char *)pre_attr->value);
++
++		} else if (Is (XNLineSpace, pre_attr))
++			    rec->pre_attr.line_space = *(CARD32*)pre_attr->value;
++
++		else if (Is (XNCursor, pre_attr))
++		    rec->pre_attr.cursor = *(Cursor*)pre_attr->value;
++
++		else
++		    fprintf(stderr, "Unknown attr: %s b\n", pre_attr->name);
++	}
++
++
++	for (i = 0; i < (int)call_data->status_attr_num; i++, sts_attr++) {
++                if (Is (XNArea, sts_attr)) {
++		    rec->sts_attr.area = *(XRectangle*)sts_attr->value;
++                }
++                else if (Is (XNAreaNeeded, sts_attr)) {
++		    rec->sts_attr.area_needed = *(XRectangle*)sts_attr->value;
++                }
++                else if (Is (XNColormap, sts_attr)) {
++		    rec->sts_attr.cmap = *(Colormap*)sts_attr->value;
++                }
++                else if (Is (XNStdColormap, sts_attr)) {
++		    rec->sts_attr.cmap = *(Colormap*)sts_attr->value;
++		}
++                else if (Is (XNForeground, sts_attr)) {
++		    rec->sts_attr.foreground = *(CARD32*)sts_attr->value;
++                }
++		else if (Is (XNBackground, sts_attr))
++		    rec->sts_attr.background = *(CARD32*)sts_attr->value;
++
++		else if (Is (XNBackgroundPixmap, sts_attr))
++		    rec->sts_attr.bg_pixmap = *(Pixmap*)sts_attr->value;
++
++                else if (Is (XNFontSet, sts_attr)) {
++			int str_length = strlen((char *)sts_attr->value);
++
++			if (rec->sts_attr.base_font != NULL) {
++				if (Is (rec->sts_attr.base_font, sts_attr))
++					continue;
++				XFree(rec->sts_attr.base_font);
++			}
++			rec->sts_attr.base_font = (char *)malloc(str_length + 1);
++			strcpy(rec->sts_attr.base_font, (char *)sts_attr->value);
++                } else if (Is (XNLineSpace, sts_attr)) {
++			    rec->sts_attr.line_space= *(CARD32*)sts_attr->value;
++                }
++		else if (Is (XNCursor, sts_attr))
++		    rec->sts_attr.cursor = *(Cursor*)sts_attr->value;
++
++		else
++		    fprintf(stderr, "Unknown attr: %s c\n", ic_attr->name);
++	}
++
++	load_IC(rec);
++#if DEBUG && 0
++        dbg("exit StoreIC\n");
++#endif
++}
++
++void CreateIC(IMChangeICStruct *call_data)
++{
++    IC *rec;
++
++    rec = NewIC();
++    if (rec == NULL)
++      return;
++
++    StoreIC(rec, call_data);
++    call_data->icid = rec->id;
++    load_IC(rec);
++#if DEBUG && 0
++    dbg("CreateIC  .. exit\n");
++#endif
++    return;
++}
++
++#if 0
++void
++DestroyIC(call_data)
++IMChangeICStruct *call_data;
++{
++    DeleteIC(call_data->icid);
++    return;
++}
++#endif
++
++void SetIC(IMChangeICStruct * call_data)
++{
++    IC *rec = FindIC(call_data->icid);
++
++    if (rec == NULL)
++      return;
++
++    load_IC(rec);
++
++    StoreIC(rec, call_data);
++#if DEBUG
++    dbg(".... exit SetIC\n");
++#endif
++    return;
++}
++
++void GetIC(IMChangeICStruct *call_data)
++{
++    XICAttribute *ic_attr = call_data->ic_attr;
++    XICAttribute *pre_attr = call_data->preedit_attr;
++    XICAttribute *sts_attr = call_data->status_attr;
++    register int i;
++    IC *rec = FindIC(call_data->icid);
++
++    if (rec == NULL)
++      return;
++
++    ClientState *cs = &rec->cs;
++
++    for (i = 0; i < (int)call_data->ic_attr_num; i++, ic_attr++) {
++	if (Is (XNFilterEvents, ic_attr)) {
++	    ic_attr->value = (void *)malloc(sizeof(CARD32));
++	    *(CARD32*)ic_attr->value = KeyPressMask|KeyReleaseMask;
++	    ic_attr->value_length = sizeof(CARD32);
++	}
++    }
++
++    /* preedit attributes */
++    for (i = 0; i < (int)call_data->preedit_attr_num; i++, pre_attr++) {
++	if (Is (XNArea, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(XRectangle));
++            *(XRectangle*)pre_attr->value = rec->pre_attr.area;
++            pre_attr->value_length = sizeof(XRectangle);
++#if DEBUG
++            dbg("pre_attr->value: %d %d\n", rec->pre_attr.area.x, rec->pre_attr.area.y);
++#endif
++
++	} else if (Is (XNAreaNeeded, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(XRectangle));
++	    *(XRectangle*)pre_attr->value = rec->pre_attr.area_needed;
++	    pre_attr->value_length = sizeof(XRectangle);
++
++	} else if (Is (XNSpotLocation, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(XPoint));
++            *(XPoint*)pre_attr->value = cs->spot_location;
++	    pre_attr->value_length = sizeof(XPoint);
++#if DEBUG
++            dbg("over spot %d %d\n", cs->spot_location.x,  cs->spot_location.y);
++#endif
++	} else if (Is (XNFontSet, pre_attr)) {
++	    CARD16 base_len = (CARD16)strlen(rec->pre_attr.base_font);
++	    int total_len = sizeof(CARD16) + (CARD16)base_len;
++	    char *p;
++
++	    pre_attr->value = (void *)malloc(total_len);
++	    p = (char *)pre_attr->value;
++	    memmove(p, &base_len, sizeof(CARD16));
++	    p += sizeof(CARD16);
++	    strncpy(p, rec->pre_attr.base_font, base_len);
++	    pre_attr->value_length = total_len;
++
++	} else if (Is (XNForeground, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(long));
++	    *(long*)pre_attr->value = rec->pre_attr.foreground;
++	    pre_attr->value_length = sizeof(long);
++
++	} else if (Is (XNBackground, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(long));
++	    *(long*)pre_attr->value = rec->pre_attr.background;
++	    pre_attr->value_length = sizeof(long);
++
++	} else if (Is (XNLineSpace, pre_attr)) {
++	    pre_attr->value = (void *)malloc(sizeof(long));
++#if 0
++	    *(long*)pre_attr->value = rec->pre_attr.line_space;
++#endif
++	    *(long*)pre_attr->value = 18;
++	    pre_attr->value_length = sizeof(long);
++	}
++    }
++
++    /* status attributes */
++    for (i = 0; i < (int)call_data->status_attr_num; i++, sts_attr++) {
++	if (Is (XNArea, sts_attr)) {
++	    sts_attr->value = (void *)malloc(sizeof(XRectangle));
++	    *(XRectangle*)sts_attr->value = rec->sts_attr.area;
++	    sts_attr->value_length = sizeof(XRectangle);
++
++	} else if (Is (XNAreaNeeded, sts_attr)) {
++	    sts_attr->value = (void *)malloc(sizeof(XRectangle));
++	    *(XRectangle*)sts_attr->value = rec->sts_attr.area_needed;
++	    sts_attr->value_length = sizeof(XRectangle);
++
++	} else if (Is (XNFontSet, sts_attr)) {
++	    CARD16 base_len = (CARD16)strlen(rec->sts_attr.base_font);
++	    int total_len = sizeof(CARD16) + (CARD16)base_len;
++	    char *p;
++
++	    sts_attr->value = (void *)malloc(total_len);
++	    p = (char *)sts_attr->value;
++	    memmove(p, &base_len, sizeof(CARD16));
++	    p += sizeof(CARD16);
++	    strncpy(p, rec->sts_attr.base_font, base_len);
++	    sts_attr->value_length = total_len;
++
++	} else if (Is (XNForeground, sts_attr)) {
++	    sts_attr->value = (void *)malloc(sizeof(long));
++	    *(long*)sts_attr->value = rec->sts_attr.foreground;
++	    sts_attr->value_length = sizeof(long);
++
++	} else if (Is (XNBackground, sts_attr)) {
++	    sts_attr->value = (void *)malloc(sizeof(long));
++	    *(long*)sts_attr->value = rec->sts_attr.background;
++	    sts_attr->value_length = sizeof(long);
++
++	} else if (Is (XNLineSpace, sts_attr)) {
++	    sts_attr->value = (void *)malloc(sizeof(long));
++#if 0
++	    *(long*)sts_attr->value = rec->sts_attr.line_space;
++#endif
++	    *(long*)sts_attr->value = 18;
++	    sts_attr->value_length = sizeof(long);
++	}
++    }
++}
++
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/IC.h b/src/plugins/platforminputcontexts/hime/include/IC.h
+new file mode 100644
+index 0000000..d659f36
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IC.h
+@@ -0,0 +1,85 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++******************************************************************/
++typedef struct {
++    XRectangle	area;		/* area */
++    XRectangle	area_needed;	/* area needed */
++    Colormap	cmap;		/* colormap */
++    CARD32	foreground;	/* foreground */
++    CARD32	background;	/* background */
++    Pixmap	bg_pixmap;	/* background pixmap */
++    char	*base_font;	/* base font of fontset */
++    CARD32	line_space;	/* line spacing */
++    Cursor	cursor;		/* cursor */
++} PreeditAttributes;
++
++typedef struct {
++    XRectangle	area;		/* area */
++    XRectangle	area_needed;	/* area needed */
++    Colormap	cmap;		/* colormap */
++    CARD32	foreground;	/* foreground */
++    CARD32	background;	/* background */
++    Pixmap	bg_pixmap;	/* background pixmap */
++    char	*base_font;	/* base font of fontset */
++    CARD32	line_space;	/* line spacing */
++    Cursor	cursor;		/* cursor */
++} StatusAttributes;
++
++typedef struct {
++    Window	client_win;	/* client window */
++    INT32	input_style;	/* input style */
++    HIME_STATE_E im_state;
++    gboolean    b_half_full_char;
++    gboolean    fixed_pos;
++    gboolean    b_hime_protocol; // TRUE : hime    FALSE: XIM
++    gboolean    b_raise_window;
++    gboolean    use_preedit;
++    gboolean    tsin_pho_mode;
++    short       fixed_x, fixed_y;
++    short       in_method;
++    XPoint	spot_location;	/* spot location, relative to client window */
++#if USE_XIM
++    gboolean xim_preedit_started;
++#endif
++} ClientState;
++
++
++typedef struct _IC {
++#if USE_XIM
++    CARD16	id;		/* ic id */
++#endif
++    Window	focus_win;	/* focus window */
++#if USE_XIM
++    char	*resource_name;	/* resource name */
++    char	*resource_class; /* resource class */
++    PreeditAttributes pre_attr; /* preedit attributes */
++    StatusAttributes sts_attr; /* status attributes */
++#endif
++    ClientState cs;
++    struct _IC	*next;
++} IC;
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/include/IMdkit.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/IMdkit.h
+new file mode 100644
+index 0000000..6f8d673
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/IMdkit.h
+@@ -0,0 +1,144 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef _IMdkit_h
++#define _IMdkit_h
++
++#include <X11/Xmd.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* IM Attributes Name */
++#define IMModifiers		"modifiers"
++#define IMServerWindow		"serverWindow"
++#define IMServerName		"serverName"
++#define IMServerTransport	"serverTransport"
++#define IMLocale		"locale"
++#define IMInputStyles		"inputStyles"
++#define IMProtocolHandler	"protocolHandler"
++#define IMOnKeysList		"onKeysList"
++#define IMOffKeysList		"offKeysList"
++#define IMEncodingList		"encodingList"
++#define IMFilterEventMask	"filterEventMask"
++#define IMProtocolDepend	"protocolDepend"
++
++/* Masks for IM Attributes Name */
++#define I18N_IMSERVER_WIN	0x0001 /* IMServerWindow */
++#define I18N_IM_NAME		0x0002 /* IMServerName */
++#define I18N_IM_LOCALE		0x0004 /* IMLocale */
++#define I18N_IM_ADDRESS		0x0008 /* IMServerTransport */
++#define I18N_INPUT_STYLES	0x0010 /* IMInputStyles */
++#define I18N_ON_KEYS		0x0020 /* IMOnKeysList */
++#define I18N_OFF_KEYS		0x0040 /* IMOffKeysList */
++#define I18N_IM_HANDLER		0x0080 /* IMProtocolHander */
++#define I18N_ENCODINGS		0x0100 /* IMEncodingList */
++#define I18N_FILTERMASK		0x0200 /* IMFilterEventMask */
++#define I18N_PROTO_DEPEND	0x0400 /* IMProtoDepend */
++
++typedef struct
++{
++    char	*name;
++    XPointer	value;
++} XIMArg;
++
++typedef struct
++{
++    CARD32	keysym;
++    CARD32	modifier;
++    CARD32	modifier_mask;
++} XIMTriggerKey;
++
++typedef struct
++{
++    unsigned short count_keys;
++    XIMTriggerKey *keylist;
++} XIMTriggerKeys;
++
++typedef char *XIMEncoding;
++
++typedef struct
++{
++    unsigned short count_encodings;
++    XIMEncoding *supported_encodings;
++} XIMEncodings;
++
++typedef struct _XIMS *XIMS;
++
++typedef struct
++{
++    void*	(*setup) (Display *, XIMArg *);
++    Status	(*openIM) (XIMS);
++    Status	(*closeIM) (XIMS);
++    char*	(*setIMValues) (XIMS, XIMArg *);
++    char*	(*getIMValues) (XIMS, XIMArg *);
++    Status	(*forwardEvent) (XIMS, XPointer);
++    Status	(*commitString) (XIMS, XPointer);
++    int		(*callCallback) (XIMS, XPointer);
++    int		(*preeditStart) (XIMS, XPointer);
++    int		(*preeditEnd) (XIMS, XPointer);
++    int		(*syncXlib) (XIMS, XPointer);
++} IMMethodsRec, *IMMethods;
++
++typedef struct
++{
++    Display	*display;
++    int		screen;
++} IMCoreRec, *IMCore;
++
++typedef struct _XIMS
++{
++    IMMethods	methods;
++    IMCoreRec	core;
++    Bool	sync;
++    void	*protocol;
++} XIMProtocolRec;
++
++/*
++ * X function declarations.
++ */
++extern XIMS IMOpenIM (Display *, ...);
++extern Status IMCloseIM (XIMS);
++extern char *IMSetIMValues (XIMS, ...);
++extern char *IMGetIMValues (XIMS, ...);
++void IMForwardEvent (XIMS, XPointer);
++void IMCommitString (XIMS, XPointer);
++int IMCallCallback (XIMS, XPointer);
++int IMPreeditStart (XIMS, XPointer);
++int IMPreeditEnd (XIMS, XPointer);
++int IMSyncXlib (XIMS, XPointer);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* IMdkit_h */
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/include/Xi18n.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/Xi18n.h
+new file mode 100644
+index 0000000..aaf7768
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/Xi18n.h
+@@ -0,0 +1,505 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef _Xi18n_h
++#define _Xi18n_h
++#include <X11/Xlib.h>
++#include <X11/Xfuncs.h>
++#include <X11/Xos.h>
++#include "XimProto.h"
++
++/*
++ * Minor Protocol Number for Extension Protocol
++ */
++#define XIM_EXTENSION				128
++#define XIM_EXT_SET_EVENT_MASK			(0x30)
++#define	XIM_EXT_FORWARD_KEYEVENT		(0x32)
++#define	XIM_EXT_MOVE				(0x33)
++#define COMMON_EXTENSIONS_NUM   		3
++
++#include <stdlib.h>
++#include "IMdkit.h"
++
++/* XI18N Valid Attribute Name Definition */
++#define ExtForwardKeyEvent	"extForwardKeyEvent"
++#define ExtMove			"extMove"
++#define ExtSetEventMask		"extSetEventMask"
++
++/*
++ * Padding macro
++ */
++#define	IMPAD(length) ((4 - ((length)%4))%4)
++
++/*
++ * Target Atom for Transport Connection
++ */
++#define LOCALES		"LOCALES"
++#define TRANSPORT	"TRANSPORT"
++
++#define I18N_OPEN	0
++#define I18N_SET	1
++#define I18N_GET	2
++
++typedef struct
++{
++    char        *transportname;
++    int         namelen;
++    Bool        (*checkAddr) ();
++} TransportSW;
++
++typedef struct _XIMPending
++{
++    unsigned    char *p;
++    struct _XIMPending *next;
++} XIMPending;
++
++typedef struct _XimProtoHdr
++{
++    CARD8	major_opcode;
++    CARD8	minor_opcode;
++    CARD16	length;
++} XimProtoHdr;
++
++typedef struct
++{
++    CARD16	attribute_id;
++    CARD16	type;
++    CARD16	length;
++    char	*name;
++} XIMAttr;
++
++typedef struct
++{
++    CARD16	attribute_id;
++    CARD16	type;
++    CARD16	length;
++    char	*name;
++} XICAttr;
++
++typedef struct
++{
++    int		attribute_id;
++    CARD16	name_length;
++    char	*name;
++    int		value_length;
++    void	*value;
++    int		type;
++} XIMAttribute;
++
++typedef struct
++{
++    int		attribute_id;
++    CARD16	name_length;
++    char	*name;
++    int		value_length;
++    void	*value;
++    int		type;
++} XICAttribute;
++
++typedef struct
++{
++    int		length;
++    char	*name;
++} XIMStr;
++
++typedef struct
++{
++    CARD16	major_opcode;
++    CARD16	minor_opcode;
++    CARD16	length;
++    char	*name;
++} XIMExt;
++
++typedef struct _Xi18nClient
++{
++    int		connect_id;
++    CARD8	byte_order;
++    /*
++       '?': initial value
++       'B': for Big-Endian
++       'l': for little-endian
++     */
++    int		sync;
++    XIMPending  *pending;
++    void *trans_rec;		/* contains transport specific data  */
++    struct _Xi18nClient *next;
++} Xi18nClient;
++
++typedef struct _Xi18nCore *Xi18n;
++
++/*
++ * Callback Struct for XIM Protocol
++ */
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++} IMAnyStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD8	byte_order;
++    CARD16	major_version;
++    CARD16	minor_version;
++} IMConnectStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++} IMDisConnectStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    XIMStr	lang;
++} IMOpenStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++} IMCloseStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	number;
++    XIMStr	*extension;
++} IMQueryExtensionStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	number;
++    char	**im_attr_list;
++} IMGetIMValuesStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD16	preedit_attr_num;
++    CARD16	status_attr_num;
++    CARD16	ic_attr_num;
++    XICAttribute *preedit_attr;
++    XICAttribute *status_attr;
++    XICAttribute *ic_attr;
++} IMChangeICStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++} IMDestroyICStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD16	length;
++    char	*commit_string;
++} IMResetICStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++} IMChangeFocusStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    BITMASK16	sync_bit;
++    CARD16	serial_number;
++    XEvent	event;
++} IMForwardEventStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD16	flag;
++    KeySym	keysym;
++    char	*commit_string;
++} IMCommitStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD32	flag;
++    CARD32	key_index;
++    CARD32	event_mask;
++} IMTriggerNotifyStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	encoding_number;
++    XIMStr	*encoding;	/* name information */
++    CARD16	encoding_info_number;
++    XIMStr	*encodinginfo;	/* detailed information */
++    CARD16	category;	/* #0 for name, #1 for detail */
++    INT16	enc_index;	/* index of the encoding determined */
++} IMEncodingNegotiationStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD32	flag;
++    CARD32	forward_event_mask;
++    CARD32	sync_event_mask;
++} IMSetEventMaskStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD32	filter_event_mask;
++    CARD32	intercept_event_mask;
++    CARD32	select_event_mask;
++    CARD32	forward_event_mask;
++    CARD32	sync_event_mask;
++} IMExtSetEventMaskStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    CARD16	x;
++    CARD16	y;
++} IMMoveStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    BITMASK16	flag;
++    CARD16	error_code;
++    CARD16	str_length;
++    CARD16	error_type;
++    char	*error_detail;
++} IMErrorStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++} IMPreeditStateStruct;
++
++/* Callbacks */
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++} IMGeometryCBStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    union
++    {
++	int return_value;			/* PreeditStart */
++	XIMPreeditDrawCallbackStruct draw;	/* PreeditDraw */
++	XIMPreeditCaretCallbackStruct caret; 	/* PreeditCaret */
++    } todo;
++} IMPreeditCBStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    union
++    {
++	XIMStatusDrawCallbackStruct draw;	/* StatusDraw */
++    } todo;
++} IMStatusCBStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++    XIMStringConversionCallbackStruct strconv;
++} IMStrConvCBStruct;
++
++typedef struct
++{
++    int		major_code;
++    int		minor_code;
++    CARD16	connect_id;
++    CARD16	icid;
++} IMSyncXlibStruct;
++
++typedef union _IMProtocol
++{
++    int	major_code;
++    IMAnyStruct any;
++    IMConnectStruct imconnect;
++    IMDisConnectStruct imdisconnect;
++    IMOpenStruct imopen;
++    IMCloseStruct imclose;
++    IMQueryExtensionStruct queryext;
++    IMGetIMValuesStruct getim;
++    IMEncodingNegotiationStruct encodingnego;
++    IMExtSetEventMaskStruct extsetevent;
++    IMMoveStruct extmove;
++    IMSetEventMaskStruct setevent;
++    IMChangeICStruct changeic;
++    IMDestroyICStruct destroyic;
++    IMResetICStruct resetic;
++    IMChangeFocusStruct changefocus;
++    IMCommitStruct commitstring;
++    IMForwardEventStruct forwardevent;
++    IMTriggerNotifyStruct triggernotify;
++    IMPreeditStateStruct preedit_state;
++    IMErrorStruct imerror;
++    IMGeometryCBStruct geometry_callback;
++    IMPreeditCBStruct preedit_callback;
++    IMStatusCBStruct status_callback;
++    IMStrConvCBStruct strconv_callback;
++    IMSyncXlibStruct sync_xlib;
++    long pad[32];
++} IMProtocol;
++
++typedef int (*IMProtoHandler) (XIMS, IMProtocol*);
++
++#define DEFAULT_FILTER_MASK	(KeyPressMask)
++
++/* Xi18nAddressRec structure */
++typedef struct _Xi18nAddressRec
++{
++    Display	*dpy;
++    CARD8	im_byteOrder;	/* byte order 'B' or 'l' */
++    /* IM Values */
++    long	imvalue_mask;
++    Window	im_window;	/* IMServerWindow */
++    char	*im_name;	/* IMServerName */
++    char	*im_locale;	/* IMLocale */
++    char	*im_addr;	/* IMServerTransport */
++    XIMStyles	input_styles;	/* IMInputStyles */
++    XIMTriggerKeys on_keys;	/* IMOnKeysList */
++    XIMTriggerKeys off_keys;	/* IMOffKeysList */
++    XIMEncodings encoding_list; /* IMEncodingList */
++    IMProtoHandler improto;	/* IMProtocolHander */
++    long	filterevent_mask; /* IMFilterEventMask */
++    /* XIM_SERVERS target Atoms */
++    Atom	selection;
++    Atom	Localename;
++    Atom	Transportname;
++    /* XIM/XIC Attr */
++    int		im_attr_num;
++    XIMAttr	*xim_attr;
++    int		ic_attr_num;
++    XICAttr	*xic_attr;
++    CARD16	preeditAttr_id;
++    CARD16	statusAttr_id;
++    CARD16	separatorAttr_id;
++    /* XIMExtension List */
++    int		ext_num;
++    XIMExt	extension[COMMON_EXTENSIONS_NUM];
++    /* transport specific connection address */
++    void	*connect_addr;
++    /* actual data is defined:
++       XSpecRec in Xi18nX.h for X-based connection.
++       TransSpecRec in Xi18nTr.h for Socket-based connection.
++     */
++    /* clients table */
++    Xi18nClient *clients;
++    Xi18nClient *free_clients;
++} Xi18nAddressRec;
++
++typedef struct _Xi18nMethodsRec
++{
++    Bool (*begin) (XIMS);
++    Bool (*end) (XIMS);
++    Bool (*send) (XIMS, CARD16, unsigned char*, long);
++    Bool (*wait) (XIMS, CARD16, CARD8, CARD8);
++    Bool (*disconnect) (XIMS, CARD16);
++} Xi18nMethodsRec;
++
++typedef struct _Xi18nCore
++{
++    Xi18nAddressRec address;
++    Xi18nMethodsRec methods;
++} Xi18nCore;
++
++#endif
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/include/XimProto.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/XimProto.h
+new file mode 100644
+index 0000000..e3ed168
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/include/XimProto.h
+@@ -0,0 +1,230 @@
++/* $XConsortium: XimProto.h,v 1.2 94/01/20 18:02:24 rws Exp $ */
++/******************************************************************
++
++           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of FUJITSU LIMITED
++not be used in advertising or publicity pertaining to distribution
++of the software without specific, written prior permission.
++FUJITSU LIMITED makes no representations about the suitability of
++this software for any purpose.
++It is provided "as is" without express or implied warranty.
++
++FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
++USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
++OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Takashi Fujiwara     FUJITSU LIMITED
++                               fujiwara@a80.tech.yk.fujitsu.co.jp
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef _XIMPROTO_H
++#define _XIMPROTO_H
++
++/*
++ * Default Preconnection selection target
++ */
++#define XIM_SERVERS		"XIM_SERVERS"
++#define XIM_LOCALES		"LOCALES"
++#define XIM_TRANSPORT		"TRANSPORT"
++
++/*
++ * categories in XIM_SERVERS
++ */
++#define XIM_SERVER_CATEGORY	"@server="
++#define XIM_LOCAL_CATEGORY	"@locale="
++#define XIM_TRANSPORT_CATEGORY	"@transport="
++
++/*
++ * Xim implementation revision
++ */
++#define PROTOCOLMAJORVERSION		0
++#define PROTOCOLMINORVERSION		0
++
++/*
++ * Major Protocol number
++ */
++#define	XIM_CONNECT			  1
++#define	XIM_CONNECT_REPLY		  2
++#define	XIM_DISCONNECT			  3
++#define	XIM_DISCONNECT_REPLY		  4
++
++#define XIM_AUTH_REQUIRED		 10
++#define XIM_AUTH_REPLY			 11
++#define XIM_AUTH_NEXT			 12
++#define XIM_AUTH_SETUP			 13
++#define XIM_AUTH_NG			 14
++
++#define	XIM_ERROR			 20
++
++#define	XIM_OPEN			 30
++#define	XIM_OPEN_REPLY			 31
++#define	XIM_CLOSE			 32
++#define	XIM_CLOSE_REPLY			 33
++#define	XIM_REGISTER_TRIGGERKEYS	 34
++#define	XIM_TRIGGER_NOTIFY		 35
++#define	XIM_TRIGGER_NOTIFY_REPLY	 36
++#define	XIM_SET_EVENT_MASK		 37
++#define	XIM_ENCODING_NEGOTIATION	 38
++#define	XIM_ENCODING_NEGOTIATION_REPLY	 39
++#define	XIM_QUERY_EXTENSION		 40
++#define	XIM_QUERY_EXTENSION_REPLY	 41
++#define	XIM_SET_IM_VALUES		 42
++#define	XIM_SET_IM_VALUES_REPLY		 43
++#define	XIM_GET_IM_VALUES		 44
++#define	XIM_GET_IM_VALUES_REPLY		 45
++
++#define XIM_CREATE_IC			 50
++#define	XIM_CREATE_IC_REPLY		 51
++#define	XIM_DESTROY_IC			 52
++#define	XIM_DESTROY_IC_REPLY		 53
++#define XIM_SET_IC_VALUES		 54
++#define	XIM_SET_IC_VALUES_REPLY		 55
++#define XIM_GET_IC_VALUES		 56
++#define XIM_GET_IC_VALUES_REPLY		 57
++#define	XIM_SET_IC_FOCUS		 58
++#define	XIM_UNSET_IC_FOCUS		 59
++#define	XIM_FORWARD_EVENT		 60
++#define	XIM_SYNC			 61
++#define	XIM_SYNC_REPLY			 62
++#define	XIM_COMMIT			 63
++#define	XIM_RESET_IC			 64
++#define	XIM_RESET_IC_REPLY		 65
++
++#define	XIM_GEOMETRY			 70
++#define	XIM_STR_CONVERSION		 71
++#define	XIM_STR_CONVERSION_REPLY	 72
++#define	XIM_PREEDIT_START		 73
++#define	XIM_PREEDIT_START_REPLY		 74
++#define	XIM_PREEDIT_DRAW		 75
++#define	XIM_PREEDIT_CARET		 76
++#define XIM_PREEDIT_CARET_REPLY		 77
++#define	XIM_PREEDIT_DONE		 78
++#define	XIM_STATUS_START		 79
++#define	XIM_STATUS_DRAW			 80
++#define	XIM_STATUS_DONE			 81
++
++/*
++ * values for the flag of XIM_ERROR
++ */
++#define	XIM_IMID_VALID			0x0001
++#define	XIM_ICID_VALID			0x0002
++
++/*
++ * XIM Error Code
++ */
++#define XIM_BadAlloc			1
++#define XIM_BadStyle			2
++#define XIM_BadClientWindow		3
++#define XIM_BadFocusWindow		4
++#define XIM_BadArea			5
++#define XIM_BadSpotLocation		6
++#define XIM_BadColormap			7
++#define XIM_BadAtom			8
++#define XIM_BadPixel			9
++#define XIM_BadPixmap			10
++#define XIM_BadName			11
++#define XIM_BadCursor			12
++#define XIM_BadProtocol			13
++#define XIM_BadForeground		14
++#define XIM_BadBackground		15
++#define XIM_LocaleNotSupported		16
++#define XIM_BadSomething		999
++
++/*
++ * byte order
++ */
++#define BIGENDIAN	(CARD8) 0x42	/* MSB first */
++#define LITTLEENDIAN	(CARD8) 0x6c	/* LSB first */
++
++/*
++ * values for the type of XIMATTR & XICATTR
++ */
++#define	XimType_SeparatorOfNestedList	0
++#define	XimType_CARD8			1
++#define	XimType_CARD16			2
++#define	XimType_CARD32			3
++#define	XimType_STRING8			4
++#define	XimType_Window			5
++#define	XimType_XIMStyles		10
++#define	XimType_XRectangle		11
++#define	XimType_XPoint			12
++#define XimType_XFontSet		13
++#define XimType_XIMOptions		14
++#define XimType_XIMHotKeyTriggers	15
++#define XimType_XIMHotKeyState		16
++#define XimType_XIMStringConversion	17
++#define XimType_XIMValuesList		18
++#define	XimType_NEST			0x7FFF
++
++/*
++ * values for the category of XIM_ENCODING_NEGOTIATON_REPLY
++ */
++#define	XIM_Encoding_NameCategory	0
++#define	XIM_Encoding_DetailCategory	1
++
++/*
++ * value for the index of XIM_ENCODING_NEGOTIATON_REPLY
++ */
++#define	XIM_Default_Encoding_IDX	-1
++
++/*
++ * value for the flag of XIM_FORWARD_EVENT, XIM_COMMIT
++ */
++#define XimSYNCHRONUS		  0x0001
++#define XimLookupChars		  0x0002
++#define XimLookupKeySym		  0x0004
++#define XimLookupBoth		  0x0006
++
++/*
++ * request packet header size
++ */
++#define XIM_HEADER_SIZE						\
++	  sizeof(CARD8)		/* sizeof mejor-opcode */	\
++	+ sizeof(CARD8)		/* sizeof minor-opcode */	\
++	+ sizeof(INT16)		/* sizeof length */
++
++/*
++ * Client Message data size
++ */
++#define	XIM_CM_DATA_SIZE	20
++
++/*
++ * XIM data structure
++ */
++typedef CARD16	BITMASK16;
++typedef CARD32	BITMASK32;
++typedef CARD32	EVENTMASK;
++
++typedef CARD16	XIMID;		/* Input Method ID */
++typedef CARD16	XICID;		/* Input Context ID */
++
++/*
++ * Padding macro
++ */
++#define	XIM_PAD(length) ((4 - ((length) % 4)) % 4)
++
++#define XIM_SET_PAD(ptr, length)					\
++    {									\
++	register int	 Counter = XIM_PAD((int)length);		\
++	if (Counter) {							\
++	    register char	*Ptr = (char *)(ptr) + (length);	\
++	    length += Counter;						\
++	    for (; Counter; --Counter, ++Ptr)				\
++		*Ptr = '\0';						\
++	}								\
++    }
++
++#endif
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.c
+new file mode 100644
+index 0000000..9b49794
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.c
+@@ -0,0 +1,2466 @@
++/******************************************************************
++Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
++
++                        All Rights Reserved
++
++Permission to use, copy, modify, and distribute this software and its
++documentation for any purpose and without fee is hereby granted,
++provided that the above copyright notice appear in all copies and that
++both that copyright notice and this permission notice appear in
++supporting documentation, and that the names of Digital or MIT not be
++used in advertising or publicity pertaining to distribution of the
++software without specific, written prior permission.
++
++DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
++ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
++ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
++WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
++ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
++SOFTWARE.
++
++  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
++                             miyamoto@jrd.dec.com
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlibint.h>
++#include <stdlib.h>
++#include "FrameMgr.h"
++
++/* Convenient macro */
++
++#define _UNIT(n)   ((int)(n) & 0xFF)
++#define _NUMBER(n) (((int)(n) >> 8) & 0xFF)
++
++/* For byte swapping */
++
++#define Swap16(p, n) ((p)->byte_swap ?       \
++(((n) << 8 & 0xFF00) | \
++ ((n) >> 8 & 0xFF)     \
++) : n)
++#define Swap32(p, n) ((p)->byte_swap ?            \
++        (((n) << 24 & 0xFF000000) | \
++         ((n) <<  8 & 0xFF0000) |   \
++         ((n) >>  8 & 0xFF00) |     \
++         ((n) >> 24 & 0xFF)         \
++        ) : n)
++#define Swap64(p, n) ((p)->byte_swap ?            \
++        (((n) << 56 & 0xFF00000000000000) | \
++         ((n) << 40 & 0xFF000000000000) |   \
++         ((n) << 24 & 0xFF0000000000) |     \
++         ((n) <<  8 & 0xFF00000000) |       \
++         ((n) >>  8 & 0xFF000000) |         \
++         ((n) >> 24 & 0xFF0000) |           \
++         ((n) >> 40 & 0xFF00) |             \
++         ((n) >> 56 & 0xFF)                 \
++        ) : n)
++
++/* Type definition */
++
++typedef struct _Iter *Iter;
++
++typedef struct _FrameInst *FrameInst;
++
++typedef union
++{
++    int num; 		/* For BARRAY */
++    FrameInst fi; 	/* For POINTER */
++    Iter iter; 		/* For ITER */
++} ExtraDataRec, *ExtraData;
++
++typedef struct _Chain
++{
++    ExtraDataRec d;
++    int frame_no;
++    struct _Chain *next;
++} ChainRec, *Chain;
++
++typedef struct _ChainMgr
++{
++    Chain top;
++    Chain tail;
++} ChainMgrRec, *ChainMgr;
++
++typedef struct _ChainIter
++{
++    Chain cur;
++} ChainIterRec, *ChainIter;
++
++typedef struct _FrameIter
++{
++    Iter iter;
++    Bool counting;
++    unsigned int counter;
++    int end;
++    struct _FrameIter* next;
++} FrameIterRec, *FrameIter;
++
++typedef struct _FrameInst
++{
++    XimFrame template;
++    ChainMgrRec cm;
++    int cur_no;
++} FrameInstRec;
++
++typedef void (*IterStartWatchProc) (Iter it, void *client_data);
++
++typedef struct _Iter
++{
++    XimFrame template;
++    int max_count;
++    Bool allow_expansion;
++    ChainMgrRec cm;
++    int cur_no;
++    IterStartWatchProc start_watch_proc;
++    void *client_data;
++    Bool start_counter;
++} IterRec;
++
++typedef struct _FrameMgr
++{
++    XimFrame frame;
++    FrameInst fi;
++    char *area;
++    int idx;
++    Bool byte_swap;
++    int total_size;
++    FrameIter iters;
++} FrameMgrRec;
++
++typedef union
++{
++    int num;           /* For BARRAY and PAD */
++    struct
++    {          /* For COUNTER_* */
++        Iter iter;
++        Bool is_byte_len;
++    } counter;
++} XimFrameTypeInfoRec, *XimFrameTypeInfo;
++
++/* Special values */
++#define NO_VALUE -1
++#define NO_VALID_FIELD -2
++
++static FrameInst FrameInstInit(XimFrame frame);
++static void FrameInstFree(FrameInst fi);
++static XimFrameType FrameInstGetNextType(FrameInst fi, XimFrameTypeInfo info);
++static XimFrameType FrameInstPeekNextType(FrameInst fi, XimFrameTypeInfo info);
++static FmStatus FrameInstSetSize(FrameInst fi, int num);
++static FmStatus FrameInstSetIterCount(FrameInst fi, int num);
++static int FrameInstGetTotalSize(FrameInst fi);
++static void FrameInstReset(FrameInst fi);
++
++static Iter IterInit(XimFrame frame, int count);
++static void IterFree(Iter it);
++static int FrameInstGetSize(FrameInst fi);
++static int IterGetSize(Iter it);
++static XimFrameType IterGetNextType(Iter it, XimFrameTypeInfo info);
++static XimFrameType IterPeekNextType(Iter it, XimFrameTypeInfo info);
++static FmStatus IterSetSize(Iter it, int num);
++static FmStatus IterSetIterCount(Iter it, int num);
++static int IterGetTotalSize(Iter it);
++static void IterReset(Iter it);
++static Bool IterIsLoopEnd(Iter it, Bool* myself);
++static void IterSetStartWatch(Iter it, IterStartWatchProc proc, void* client_data);
++static void _IterStartWatch(Iter it, void* client_data);
++
++static ExtraData ChainMgrGetExtraData(ChainMgr cm, int frame_no);
++static ExtraData ChainMgrSetData(ChainMgr cm, int frame_no,
++                                 ExtraDataRec data);
++static Bool ChainIterGetNext(ChainIter ci, int* frame_no, ExtraData d);
++static int _FrameInstIncrement(XimFrame frame, int count);
++static int _FrameInstDecrement(XimFrame frame, int count);
++static int _FrameInstGetItemSize(FrameInst fi, int cur_no);
++static Bool FrameInstIsIterLoopEnd(FrameInst fi);
++
++static FrameIter _FrameMgrAppendIter(FrameMgr fm, Iter it, int end);
++static FrameIter _FrameIterCounterIncr(FrameIter fitr, int i);
++static void _FrameMgrRemoveIter(FrameMgr fm, FrameIter it);
++static Bool _FrameMgrIsIterLoopEnd(FrameMgr fm);
++static Bool _FrameMgrProcessPadding(FrameMgr fm, FmStatus* status);
++
++#define IterGetIterCount(it) ((it)->allow_expansion ? \
++NO_VALUE : (it)->max_count)
++
++#define IterFixIteration(it) ((it)->allow_expansion = False)
++
++#define IterSetStarter(it) ((it)->start_counter = True)
++
++#define ChainMgrInit(cm) (cm)->top = (cm)->tail = NULL
++#define ChainMgrFree(cm)                \
++{                                       \
++    Chain tmp;                          \
++    Chain cur = (cm)->top;              \
++					\
++    while (cur)                         \
++    {                                   \
++        tmp = cur->next;                \
++        Xfree (cur);                    \
++	cur = tmp;                      \
++    }                                   \
++}
++
++#define ChainIterInit(ci, cm)           \
++{                                       \
++    (ci)->cur = (cm)->top;              \
++}
++
++/* ChainIterFree has nothing to do. */
++#define ChainIterFree(ci)
++
++#define FrameInstIsEnd(fi) ((fi)->template[(fi)->cur_no].type == EOL)
++
++FrameMgr FrameMgrInit (XimFrame frame, char* area, Bool byte_swap)
++{
++    FrameMgr fm;
++
++    fm = (FrameMgr) Xmalloc (sizeof (FrameMgrRec));
++
++    fm->frame = frame;
++    fm->fi = FrameInstInit (frame);
++    fm->area = (char *) area;
++    fm->idx = 0;
++    fm->byte_swap = byte_swap;
++    fm->total_size = NO_VALUE;
++    fm->iters = NULL;
++
++    return fm;
++}
++
++void FrameMgrInitWithData (FrameMgr fm,
++                           XimFrame frame,
++                           void * area,
++                           Bool byte_swap)
++{
++    fm->frame = frame;
++    fm->fi = FrameInstInit (frame);
++    fm->area = (char *) area;
++    fm->idx = 0;
++    fm->byte_swap = byte_swap;
++    fm->total_size = NO_VALUE;
++}
++
++void FrameMgrFree (FrameMgr fm)
++{
++    FrameIter p, cur;
++
++    p = fm->iters;
++    cur = p;
++
++    while (p)
++    {
++        p = p->next;
++        Xfree (cur);
++        cur = p;
++    }
++    /*endwhile*/
++
++    FrameInstFree (fm->fi);
++    Xfree (fm);
++}
++
++FmStatus FrameMgrSetBuffer (FrameMgr fm, void* area)
++{
++    if (fm->area)
++        return FmBufExist;
++    fm->area = (char *) area;
++    return FmSuccess;
++}
++
++FmStatus _FrameMgrPutToken (FrameMgr fm, void *data, int data_size)
++{
++    XimFrameType type;
++    XimFrameTypeInfoRec info;
++
++    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
++        return FmNoMoreData;
++    /*endif*/
++
++    type = FrameInstGetNextType(fm->fi, &info);
++
++    if (type & COUNTER_MASK)
++    {
++        unsigned long input_length;
++
++        if (info.counter.is_byte_len)
++        {
++            if ((input_length = IterGetTotalSize (info.counter.iter))
++                    == NO_VALUE)
++            {
++                return FmCannotCalc;
++            }
++            /*endif*/
++        }
++        else
++        {
++            if ((input_length = IterGetIterCount (info.counter.iter))
++                == NO_VALUE)
++            {
++                return FmCannotCalc;
++            }
++            /*endif*/
++        }
++        /*endif*/
++        switch (type)
++        {
++        case COUNTER_BIT8:
++            *(CARD8 *) (fm->area + fm->idx) = input_length;
++            fm->idx++;
++            break;
++
++        case COUNTER_BIT16:
++            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, input_length);
++            fm->idx += 2;
++            break;
++
++        case COUNTER_BIT32:
++            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, input_length);
++            fm->idx += 4;
++            break;
++
++#if defined(_NEED64BIT)
++        case COUNTER_BIT64:
++            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, input_length);
++            fm->idx += 8;
++            break;
++#endif
++	default:
++	    break;
++        }
++        /*endswitch*/
++        _FrameMgrPutToken(fm, data, data_size);
++        return FmSuccess;
++    }
++    /*endif*/
++
++    switch (type)
++    {
++    case BIT8:
++        if (data_size == sizeof (unsigned char))
++        {
++            unsigned long num = *(unsigned char *) data;
++            *(CARD8 *) (fm->area + fm->idx) = num;
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            unsigned long num = *(unsigned short *) data;
++            *(CARD8 *) (fm->area + fm->idx) = num;
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            unsigned long num = *(unsigned int *) data;
++            *(CARD8 *) (fm->area + fm->idx) = num;
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            unsigned long num = *(unsigned long *) data;
++            *(CARD8 *) (fm->area + fm->idx) = num;
++        }
++        else
++        {
++            ; /* Should never be reached */
++        }
++        /*endif*/
++        fm->idx++;
++        return FmSuccess;
++
++    case BIT16:
++        if (data_size == sizeof (unsigned char))
++        {
++            unsigned long num = *(unsigned char *) data;
++            *(CARD16*)(fm->area + fm->idx) = Swap16 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            unsigned long num = *(unsigned short *) data;
++            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            unsigned long num = *(unsigned int *) data;
++            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            unsigned long num = *(unsigned long *) data;
++            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 2;
++        return FmSuccess;
++
++    case BIT32:
++        if (data_size == sizeof (unsigned char))
++        {
++            unsigned long num = *(unsigned char *) data;
++            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            unsigned long num = *(unsigned short *) data;
++            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            unsigned long num = *(unsigned int *) data;
++            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            unsigned long num = *(unsigned long *) data;
++            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 4;
++        return FmSuccess;
++
++#if defined(_NEED64BIT)
++    case BIT64:
++        if (data_size == sizeof (unsigned char))
++        {
++            unsigned long num = *(unsigned char *) data;
++            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            unsigned long num = *(unsigned short *) data;
++            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            unsigned long num = *(unsigned int *) data;
++            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            unsigned long num = *(unsigned long *) data;
++            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 4;
++        return FmSuccess;
++#endif
++
++    case BARRAY:
++        if (info.num == NO_VALUE)
++            return FmInvalidCall;
++        /*endif*/
++        if (info.num > 0)
++        {
++            bcopy (*(char **) data, fm->area + fm->idx, info.num);
++            fm->idx += info.num;
++        }
++        /*endif*/
++        return FmSuccess;
++
++    case PADDING:
++        if (info.num == NO_VALUE)
++            return FmInvalidCall;
++        /*endif*/
++        fm->idx += info.num;
++        return _FrameMgrPutToken(fm, data, data_size);
++
++    case ITER:
++        return FmInvalidCall;
++
++    case EOL:
++        return FmEOD;
++    default:
++	break;
++    }
++    /*endswitch*/
++    return (FmStatus) NULL;  /* Should never be reached */
++}
++
++FmStatus _FrameMgrGetToken (FrameMgr fm , void* data, int data_size)
++{
++    XimFrameType type;
++    static XimFrameTypeInfoRec info;  /* memory */
++    FrameIter fitr;
++
++    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
++        return FmNoMoreData;
++    /*endif*/
++
++    type = FrameInstGetNextType(fm->fi, &info);
++
++    if (type & COUNTER_MASK)
++    {
++        int end=0;
++        FrameIter client_data;
++
++        type &= ~COUNTER_MASK;
++        switch (type)
++        {
++        case BIT8:
++            end = *(CARD8 *) (fm->area + fm->idx);
++            break;
++
++        case BIT16:
++            end = Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
++            break;
++
++        case BIT32:
++            end = Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
++            break;
++
++#if defined(_NEED64BIT)
++        case BIT64:
++            end = Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
++            break;
++#endif
++	default:
++	    break;
++        }
++        /*endswitch*/
++
++        if ((client_data = _FrameMgrAppendIter (fm, info.counter.iter, end)))
++        {
++            IterSetStarter (info.counter.iter);
++            IterSetStartWatch (info.counter.iter,
++                               _IterStartWatch,
++                               (void *) client_data);
++        }
++        /*endif*/
++    }
++    /*endif*/
++
++    type &= ~COUNTER_MASK;
++    switch (type)
++    {
++    case BIT8:
++        if (data_size == sizeof (unsigned char))
++        {
++            *(unsigned char*) data = *(CARD8 *) (fm->area + fm->idx);
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            *(unsigned short *) data = *(CARD8 *) (fm->area + fm->idx);
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            *(unsigned int *) data = *(CARD8 *) (fm->area + fm->idx);
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            *(unsigned long *) data = *(CARD8 *) (fm->area + fm->idx);
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx++;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, 1/*BIT8*/)))
++            _FrameMgrRemoveIter (fm, fitr);
++        /*endif*/
++        return FmSuccess;
++
++    case BIT16:
++        if (data_size == sizeof (unsigned char))
++        {
++            *(unsigned char *) data =
++                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            *(unsigned short *) data =
++                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            *(unsigned int *) data =
++                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            *(unsigned long *) data =
++                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 2;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, 2/*BIT16*/)))
++            _FrameMgrRemoveIter(fm, fitr);
++        /*endif*/
++        return FmSuccess;
++
++    case BIT32:
++        if (data_size == sizeof (unsigned char))
++        {
++            *(unsigned char *) data =
++                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            *(unsigned short *) data =
++                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            *(unsigned int *) data =
++                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            *(unsigned long *) data =
++                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 4;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, 4/*BIT32*/)))
++            _FrameMgrRemoveIter (fm, fitr);
++        /*endif*/
++        return FmSuccess;
++
++#if defined(_NEED64BIT)
++    case BIT64:
++        if (data_size == sizeof (unsigned char))
++        {
++            *(unsigned char *) data =
++                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned short))
++        {
++            *(unsigned short *) data =
++                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned int))
++        {
++            *(unsigned int *) data =
++                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
++        }
++        else if (data_size == sizeof (unsigned long))
++        {
++            *(unsigned long *) data =
++                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
++        }
++        else
++        {
++            ; /* Should never reached */
++        }
++        /*endif*/
++        fm->idx += 8;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, 8/*BIT64*/)))
++            _FrameMgrRemoveIter (fm, fitr);
++        /*endif*/
++        return FmSuccess;
++#endif
++
++    case BARRAY:
++        if (info.num == NO_VALUE)
++            return FmInvalidCall;
++        /*endif*/
++        if (info.num > 0)
++        {
++            *(char **) data = fm->area + fm->idx;
++
++            fm->idx += info.num;
++            if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
++                _FrameMgrRemoveIter (fm, fitr);
++            /*endif*/
++        }
++        else
++        {
++            *(char **) data = NULL;
++        }
++        /*endif*/
++        return FmSuccess;
++
++    case PADDING:
++        if (info.num == NO_VALUE)
++            return FmInvalidCall;
++        /*endif*/
++        fm->idx += info.num;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
++            _FrameMgrRemoveIter (fm, fitr);
++        /*endif*/
++        return _FrameMgrGetToken (fm, data, data_size);
++
++    case ITER:
++        return FmInvalidCall; 	/* if comes here, it's a bug! */
++
++    case EOL:
++        return FmEOD;
++    default:
++	break;
++    }
++    /*endswitch*/
++    return (FmStatus) NULL;  /* Should never be reached */
++}
++
++FmStatus FrameMgrSetSize (FrameMgr fm, int barray_size)
++{
++    if (FrameInstSetSize (fm->fi, barray_size) == FmSuccess)
++        return FmSuccess;
++    /*endif*/
++    return FmNoMoreData;
++}
++
++FmStatus FrameMgrSetIterCount (FrameMgr fm, int count)
++{
++    if (FrameInstSetIterCount (fm->fi, count) == FmSuccess)
++        return FmSuccess;
++    /*endif*/
++    return FmNoMoreData;
++}
++
++FmStatus FrameMgrSetTotalSize (FrameMgr fm, int total_size)
++{
++    fm->total_size = total_size;
++    return FmSuccess;
++}
++
++int FrameMgrGetTotalSize (FrameMgr fm)
++{
++    return FrameInstGetTotalSize (fm->fi);
++}
++
++int FrameMgrGetSize (FrameMgr fm)
++{
++    register int ret_size;
++
++    ret_size = FrameInstGetSize (fm->fi);
++    if (ret_size == NO_VALID_FIELD)
++        return NO_VALUE;
++    /*endif*/
++    return ret_size;
++}
++
++FmStatus FrameMgrSkipToken (FrameMgr fm, int skip_count)
++{
++    XimFrameType type;
++    XimFrameTypeInfoRec info;
++    register int i;
++
++    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
++        return FmNoMoreData;
++    /*endif*/
++    for (i = 0;  i < skip_count;  i++)
++    {
++        type = FrameInstGetNextType (fm->fi, &info);
++        type &= ~COUNTER_MASK;
++
++        switch (type)
++        {
++        case BIT8:
++            fm->idx++;
++            break;
++
++        case BIT16:
++            fm->idx += 2;
++            break;
++
++        case BIT32:
++            fm->idx += 4;
++            break;
++
++        case BIT64:
++            fm->idx += 8;
++            break;
++
++        case BARRAY:
++            if (info.num == NO_VALUE)
++                return FmInvalidCall;
++            /*endif*/
++            fm->idx += info.num;
++            break;
++
++        case PADDING:
++            if (info.num == NO_VALUE)
++                return FmInvalidCall;
++            /*endif*/
++            fm->idx += info.num;
++            return FrameMgrSkipToken (fm, skip_count);
++
++        case ITER:
++            return FmInvalidCall;
++
++        case EOL:
++            return FmEOD;
++	default:
++	    break;
++        }
++        /*endswitch*/
++    }
++    /*endfor*/
++    return FmSuccess;
++}
++
++void FrameMgrReset (FrameMgr fm)
++{
++    fm->idx = 0;
++    FrameInstReset (fm->fi);
++}
++
++Bool FrameMgrIsIterLoopEnd (FrameMgr fm, FmStatus* status)
++{
++    do
++    {
++        if (_FrameMgrIsIterLoopEnd (fm))
++            return  True;
++        /*endif*/
++    }
++    while (_FrameMgrProcessPadding (fm, status));
++
++    return False;
++}
++
++
++/* Internal routines */
++
++static Bool _FrameMgrIsIterLoopEnd (FrameMgr fm)
++{
++    return FrameInstIsIterLoopEnd (fm->fi);
++}
++
++static Bool _FrameMgrProcessPadding (FrameMgr fm, FmStatus* status)
++{
++    XimFrameTypeInfoRec info;
++    XimFrameType next_type = FrameInstPeekNextType (fm->fi, &info);
++    FrameIter fitr;
++
++    if (next_type == PADDING)
++    {
++        if (info.num == NO_VALUE)
++        {
++            *status = FmInvalidCall;
++            return True;
++        }
++        /*endif*/
++        next_type = FrameInstGetNextType (fm->fi, &info);
++        fm->idx += info.num;
++        if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
++            _FrameMgrRemoveIter (fm, fitr);
++        /*endif*/
++        *status = FmSuccess;
++        return True;
++    }
++    /*endif*/
++    *status = FmSuccess;
++    return False;
++}
++
++static FrameInst FrameInstInit (XimFrame frame)
++{
++    FrameInst fi;
++
++    fi = (FrameInst) Xmalloc (sizeof (FrameInstRec));
++
++    fi->template = frame;
++    fi->cur_no = 0;
++    ChainMgrInit (&fi->cm);
++    return fi;
++}
++
++static void FrameInstFree (FrameInst fi)
++{
++    ChainIterRec ci;
++    int frame_no;
++    ExtraDataRec d;
++
++    ChainIterInit (&ci, &fi->cm);
++
++    while (ChainIterGetNext (&ci, &frame_no, &d))
++    {
++        register XimFrameType type;
++        type = fi->template[frame_no].type;
++        if (type == ITER)
++        {
++            if (d.iter)
++                IterFree (d.iter);
++            /*endif*/
++        }
++        else if (type == POINTER)
++        {
++            if (d.fi)
++                FrameInstFree (d.fi);
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endwhile*/
++    ChainIterFree (&ci);
++    ChainMgrFree (&fi->cm);
++    Xfree (fi);
++}
++
++static XimFrameType FrameInstGetNextType(FrameInst fi, XimFrameTypeInfo info)
++{
++    XimFrameType ret_type;
++
++    ret_type = fi->template[fi->cur_no].type;
++
++    switch (ret_type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++    case EOL:
++        fi->cur_no = _FrameInstIncrement(fi->template, fi->cur_no);
++        break;
++
++    case COUNTER_BIT8:
++    case COUNTER_BIT16:
++    case COUNTER_BIT32:
++    case COUNTER_BIT64:
++        if (info)
++        {
++            register int offset, iter_idx;
++
++            info->counter.is_byte_len =
++                (((long) fi->template[fi->cur_no].data & 0xFF)) == FmCounterByte;
++            offset = ((long) fi->template[fi->cur_no].data) >> 8;
++            iter_idx = fi->cur_no + offset;
++            if (fi->template[iter_idx].type == ITER)
++            {
++                ExtraData d;
++                ExtraDataRec dr;
++
++                if ((d = ChainMgrGetExtraData (&fi->cm, iter_idx)) == NULL)
++                {
++                    dr.iter = IterInit (&fi->template[iter_idx + 1], NO_VALUE);
++                    d = ChainMgrSetData (&fi->cm, iter_idx, dr);
++                }
++                /*endif*/
++                info->counter.iter = d->iter;
++            }
++            else
++            {
++                /* Should never reach here */
++            }
++            /*endif*/
++        }
++        /*endif*/
++        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++        break;
++
++    case BARRAY:
++        if (info)
++        {
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++                info->num = NO_VALUE;
++            else
++                info->num = d->num;
++            /*endif*/
++        }
++        /*endif*/
++        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++        break;
++
++    case PADDING:
++        if (info)
++        {
++            register int unit;
++            register int number;
++            register int size;
++            register int i;
++
++            unit = _UNIT ((long) fi->template[fi->cur_no].data);
++            number = _NUMBER ((long) fi->template[fi->cur_no].data);
++
++            i = fi->cur_no;
++            size = 0;
++            while (number > 0)
++            {
++                i = _FrameInstDecrement (fi->template, i);
++                size += _FrameInstGetItemSize (fi, i);
++                number--;
++            }
++            /*endwhile*/
++            info->num = (unit - (size%unit))%unit;
++        }
++        /*endif*/
++        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++        break;
++
++    case ITER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++            XimFrameType sub_type;
++
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++            {
++                dr.iter = IterInit (&fi->template[fi->cur_no + 1], NO_VALUE);
++                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
++            }
++            /*endif*/
++            sub_type = IterGetNextType (d->iter, info);
++            if (sub_type == EOL)
++            {
++                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++                ret_type = FrameInstGetNextType (fi, info);
++            }
++            else
++            {
++                ret_type = sub_type;
++            }
++            /*endif*/
++        }
++        break;
++
++    case POINTER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++            XimFrameType sub_type;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++            {
++                dr.fi = FrameInstInit (fi->template[fi->cur_no + 1].data);
++                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
++            }
++            /*endif*/
++            sub_type = FrameInstGetNextType (d->fi, info);
++            if (sub_type == EOL)
++            {
++                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++                ret_type = FrameInstGetNextType (fi, info);
++            }
++            else
++            {
++                ret_type = sub_type;
++            }
++            /*endif*/
++        }
++        break;
++    default:
++	break;
++    }
++    /*endswitch*/
++    return ret_type;
++}
++
++static XimFrameType FrameInstPeekNextType (FrameInst fi, XimFrameTypeInfo info)
++{
++    XimFrameType ret_type;
++
++    ret_type = fi->template[fi->cur_no].type;
++
++    switch (ret_type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++    case EOL:
++        break;
++
++    case COUNTER_BIT8:
++    case COUNTER_BIT16:
++    case COUNTER_BIT32:
++    case COUNTER_BIT64:
++        if (info)
++        {
++            register int offset;
++	    register int iter_idx;
++
++            info->counter.is_byte_len =
++                (((long) fi->template[fi->cur_no].data) & 0xFF) == FmCounterByte;
++            offset = ((long)fi->template[fi->cur_no].data) >> 8;
++            iter_idx = fi->cur_no + offset;
++            if (fi->template[iter_idx].type == ITER)
++            {
++                ExtraData d;
++                ExtraDataRec dr;
++
++                if ((d = ChainMgrGetExtraData (&fi->cm, iter_idx)) == NULL)
++                {
++                    dr.iter = IterInit (&fi->template[iter_idx + 1], NO_VALUE);
++                    d = ChainMgrSetData (&fi->cm, iter_idx, dr);
++                }
++                /*endif*/
++                info->counter.iter = d->iter;
++            }
++            else
++            {
++                /* Should not be reached here */
++            }
++            /*endif*/
++        }
++        /*endif*/
++        break;
++
++    case BARRAY:
++        if (info)
++        {
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++                info->num = NO_VALUE;
++            else
++                info->num = d->num;
++            /*endif*/
++        }
++        /*endif*/
++        break;
++
++    case PADDING:
++        if (info)
++        {
++            register int unit;
++            register int number;
++            register int size;
++            register int i;
++
++            unit = _UNIT ((long) fi->template[fi->cur_no].data);
++            number = _NUMBER ((long) fi->template[fi->cur_no].data);
++
++            i = fi->cur_no;
++            size = 0;
++            while (number > 0)
++            {
++                i = _FrameInstDecrement (fi->template, i);
++                size += _FrameInstGetItemSize (fi, i);
++                number--;
++            }
++            /*endwhile*/
++            info->num = (unit - (size%unit))%unit;
++        }
++        /*endif*/
++        break;
++
++    case ITER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++            XimFrameType sub_type;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++            {
++                dr.iter = IterInit (&fi->template[fi->cur_no + 1], NO_VALUE);
++                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
++            }
++            /*endif*/
++            sub_type = IterPeekNextType (d->iter, info);
++            if (sub_type == EOL)
++                ret_type = FrameInstPeekNextType (fi, info);
++            else
++                ret_type = sub_type;
++            /*endif*/
++        }
++        break;
++
++    case POINTER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++            XimFrameType sub_type;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
++            {
++                dr.fi = FrameInstInit (fi->template[fi->cur_no + 1].data);
++                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
++            }
++            /*endif*/
++            sub_type = FrameInstPeekNextType (d->fi, info);
++            if (sub_type == EOL)
++                ret_type = FrameInstPeekNextType (fi, info);
++            else
++                ret_type = sub_type;
++            /*endif*/
++	default:
++	    break;
++        }
++        break;
++    }
++    /*endswitch*/
++    return ret_type;
++}
++
++static Bool FrameInstIsIterLoopEnd (FrameInst fi)
++{
++    Bool ret = False;
++
++    if (fi->template[fi->cur_no].type == ITER)
++    {
++        ExtraData d = ChainMgrGetExtraData (&fi->cm, fi->cur_no);
++        Bool yourself;
++
++        if (d)
++        {
++            ret = IterIsLoopEnd (d->iter, &yourself);
++            if (ret  &&  yourself)
++                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endif*/
++    return (ret);
++}
++
++static FrameIter _FrameMgrAppendIter (FrameMgr fm, Iter it, int end)
++{
++    FrameIter p = fm->iters;
++
++    while (p  &&  p->next)
++        p = p->next;
++    /*endwhile*/
++
++    if (!p)
++    {
++        fm->iters =
++        p = (FrameIter) Xmalloc (sizeof (FrameIterRec));
++    }
++    else
++    {
++        p->next = (FrameIter) Xmalloc (sizeof (FrameIterRec));
++        p = p->next;
++    }
++    /*endif*/
++    if (p)
++    {
++        p->iter = it;
++        p->counting = False;
++        p->counter = 0;
++        p->end = end;
++        p->next = NULL;
++    }
++    /*endif*/
++    return (p);
++}
++
++static void _FrameMgrRemoveIter (FrameMgr fm, FrameIter it)
++{
++    FrameIter prev;
++    FrameIter p;
++
++    prev = NULL;
++    p = fm->iters;
++    while (p)
++    {
++        if (p == it)
++        {
++            if (prev)
++                prev->next = p->next;
++            else
++                fm->iters = p->next;
++            /*endif*/
++            Xfree (p);
++            break;
++        }
++        /*endif*/
++        prev = p;
++        p = p->next;
++    }
++    /*endwhile*/
++}
++
++static FrameIter _FrameIterCounterIncr (FrameIter fitr, int i)
++{
++    FrameIter p = fitr;
++
++    while (p)
++    {
++        if (p->counting)
++        {
++            p->counter += i;
++            if (p->counter >= p->end)
++            {
++                IterFixIteration (p->iter);
++                return (p);
++            }
++            /*endif*/
++        }
++        /*endif*/
++        p = p->next;
++    }
++    /*endwhile*/
++    return (NULL);
++}
++
++static void _IterStartWatch (Iter it, void *client_data)
++{
++    FrameIter p = (FrameIter) client_data;
++    p->counting = True;
++}
++
++static FmStatus FrameInstSetSize (FrameInst fi, int num)
++{
++    ExtraData d;
++    ExtraDataRec dr;
++    XimFrameType type;
++    register int i;
++
++    i = 0;
++    while ((type = fi->template[i].type) != EOL)
++    {
++        switch (type)
++        {
++        case BARRAY:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.num = -1;
++                d = ChainMgrSetData (&fi->cm, i, dr);
++            }
++            /*endif*/
++            if (d->num == NO_VALUE)
++            {
++                d->num = num;
++                return FmSuccess;
++            }
++            /*endif*/
++            break;
++        case ITER:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.iter = IterInit (&fi->template[i + 1], NO_VALUE);
++                d = ChainMgrSetData (&fi->cm, i, dr);
++            }
++            /*endif*/
++            if (IterSetSize (d->iter, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++            break;
++
++        case POINTER:
++            if ((d = ChainMgrGetExtraData(&fi->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit(fi->template[i + 1].data);
++                d = ChainMgrSetData(&fi->cm, i, dr);
++            }
++            /*endif*/
++            if (FrameInstSetSize(d->fi, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++            break;
++	default:
++	    break;
++        }
++        /*endswitch*/
++        i = _FrameInstIncrement(fi->template, i);
++    }
++    /*endwhile*/
++    return FmNoMoreData;
++}
++
++static int FrameInstGetSize (FrameInst fi)
++{
++    XimFrameType type;
++    register int i;
++    ExtraData d;
++    ExtraDataRec dr;
++    int ret_size;
++
++    i = fi->cur_no;
++    while ((type = fi->template[i].type) != EOL)
++    {
++        switch (type)
++        {
++        case BARRAY:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++                return NO_VALUE;
++            /*endif*/
++            return d->num;
++
++        case ITER:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.iter = IterInit (&fi->template[i + 1], NO_VALUE);
++                d = ChainMgrSetData (&fi->cm, i, dr);
++            }
++            /*endif*/
++            ret_size = IterGetSize(d->iter);
++            if (ret_size != NO_VALID_FIELD)
++                return ret_size;
++            /*endif*/
++            break;
++
++        case POINTER:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit (fi->template[i + 1].data);
++                d = ChainMgrSetData (&fi->cm, i, dr);
++            }
++            /*endif*/
++            ret_size = FrameInstGetSize (d->fi);
++            if (ret_size != NO_VALID_FIELD)
++                return ret_size;
++            /*endif*/
++            break;
++	default:
++	    break;
++        }
++        /*endswitch*/
++        i = _FrameInstIncrement (fi->template, i);
++    }
++    /*endwhile*/
++    return NO_VALID_FIELD;
++}
++
++static FmStatus FrameInstSetIterCount (FrameInst fi, int num)
++{
++    ExtraData d;
++    ExtraDataRec dr;
++    register int i;
++    XimFrameType type;
++
++    i = 0;
++    while ((type = fi->template[i].type) != EOL)
++    {
++        switch (type)
++        {
++        case ITER:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.iter = IterInit (&fi->template[i + 1], num);
++                (void)ChainMgrSetData (&fi->cm, i, dr);
++                return FmSuccess;
++            }
++            /*endif*/
++            if (IterSetIterCount (d->iter, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++            break;
++
++        case POINTER:
++            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit (fi->template[i + 1].data);
++                d = ChainMgrSetData (&fi->cm, i, dr);
++            }
++            /*endif*/
++            if (FrameInstSetIterCount (d->fi, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++            break;
++
++	default:
++	    break;
++        }
++        /*endswitch*/
++        i = _FrameInstIncrement (fi->template, i);
++    }
++    /*endwhile*/
++    return FmNoMoreData;
++}
++
++static int FrameInstGetTotalSize (FrameInst fi)
++{
++    register int size;
++    register int i;
++
++    size = 0;
++    i = 0;
++
++    while (fi->template[i].type != EOL)
++    {
++        size += _FrameInstGetItemSize (fi, i);
++        i = _FrameInstIncrement (fi->template, i);
++    }
++    /*endwhile*/
++    return size;
++}
++
++static void FrameInstReset (FrameInst fi)
++{
++    ChainIterRec ci;
++    int frame_no;
++    ExtraDataRec d;
++
++    ChainIterInit (&ci, &fi->cm);
++
++    while (ChainIterGetNext (&ci, &frame_no, &d))
++    {
++        register XimFrameType type;
++        type = fi->template[frame_no].type;
++        if (type == ITER)
++        {
++            if (d.iter)
++                IterReset (d.iter);
++            /*endif*/
++        }
++        else if (type == POINTER)
++        {
++            if (d.fi)
++                FrameInstReset (d.fi);
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endwhile*/
++    ChainIterFree (&ci);
++
++    fi->cur_no = 0;
++}
++
++static Iter IterInit (XimFrame frame, int count)
++{
++    Iter it;
++    register XimFrameType type;
++
++    it = (Iter) Xmalloc (sizeof (IterRec));
++    it->template = frame;
++    it->max_count = (count == NO_VALUE)  ?  0  :  count;
++    it->allow_expansion = (count == NO_VALUE);
++    it->cur_no = 0;
++    it->start_watch_proc = NULL;
++    it->client_data = NULL;
++    it->start_counter = False;
++
++    type = frame->type;
++    if (type & COUNTER_MASK)
++    {
++        /* COUNTER_XXX cannot be an item of a ITER */
++        Xfree (it);
++        return NULL;
++    }
++    /*endif*/
++
++    switch (type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++        /* Do nothing */
++        break;
++
++    case BARRAY:
++    case ITER:
++    case POINTER:
++        ChainMgrInit (&it->cm);
++        break;
++
++    default:
++        Xfree (it);
++        return NULL; /* This should never occur */
++    }
++    /*endswitch*/
++    return it;
++}
++
++static void IterFree (Iter it)
++{
++    switch (it->template->type)
++    {
++    case BARRAY:
++        ChainMgrFree (&it->cm);
++        break;
++
++    case ITER:
++        {
++            ChainIterRec ci;
++            int count;
++            ExtraDataRec d;
++
++            ChainIterInit (&ci, &it->cm);
++            while (ChainIterGetNext (&ci, &count, &d))
++                IterFree (d.iter);
++            /*endwhile*/
++            ChainIterFree (&ci);
++            ChainMgrFree (&it->cm);
++        }
++        break;
++
++    case POINTER:
++        {
++            ChainIterRec ci;
++            int count;
++            ExtraDataRec dr;
++
++            ChainIterInit (&ci, &it->cm);
++            while (ChainIterGetNext (&ci, &count, &dr))
++                FrameInstFree (dr.fi);
++            /*endwhile*/
++            ChainIterFree (&ci);
++            ChainMgrFree (&it->cm);
++        }
++        break;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    Xfree (it);
++}
++
++static Bool IterIsLoopEnd (Iter it, Bool *myself)
++{
++    Bool ret = False;
++    *myself = False;
++
++    if (!it->allow_expansion  &&  (it->cur_no == it->max_count))
++    {
++        *myself = True;
++        return True;
++    }
++    /*endif*/
++
++    if (it->template->type == POINTER)
++    {
++        ExtraData d = ChainMgrGetExtraData (&it->cm, it->cur_no);
++        if (d)
++        {
++            if (FrameInstIsIterLoopEnd (d->fi))
++            {
++                ret = True;
++            }
++            else
++            {
++                if (FrameInstIsEnd (d->fi))
++                {
++                    it->cur_no++;
++                    if (!it->allow_expansion  &&  it->cur_no == it->max_count)
++                    {
++                        *myself = True;
++                        ret = True;
++                    }
++                    /*endif*/
++                }
++                /*endif*/
++            }
++            /*endif*/
++        }
++        /*endif*/
++    }
++    else if (it->template->type == ITER)
++    {
++        ExtraData d = ChainMgrGetExtraData (&it->cm, it->cur_no);
++        if (d)
++        {
++            Bool yourself;
++
++            if (IterIsLoopEnd (d->iter, &yourself))
++                ret = True;
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endif*/
++
++    return ret;
++}
++
++static XimFrameType IterGetNextType (Iter it, XimFrameTypeInfo info)
++{
++    XimFrameType type = it->template->type;
++
++    if (it->start_counter)
++    {
++        (*it->start_watch_proc) (it, it->client_data);
++        it->start_counter = False;
++    }
++    /*endif*/
++    if (it->cur_no >= it->max_count)
++    {
++        if (it->allow_expansion)
++            it->max_count = it->cur_no + 1;
++        else
++            return EOL;
++        /*endif*/
++    }
++    /*endif*/
++
++    switch (type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++        it->cur_no++;
++        return type;
++
++    case BARRAY:
++        if (info)
++        {
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++                info->num = NO_VALUE;
++            else
++                info->num = d->num;
++            /*endif*/
++        }
++        /*endif*/
++        it->cur_no++;
++        return BARRAY;
++
++    case ITER:
++        {
++            XimFrameType ret_type;
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++            {
++                dr.iter = IterInit (it->template + 1, NO_VALUE);
++                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
++            }
++            /*endif*/
++
++            ret_type = IterGetNextType (d->iter, info);
++            if (ret_type == EOL)
++            {
++                it->cur_no++;
++                ret_type = IterGetNextType (it, info);
++            }
++            /*endif*/
++	    return ret_type;
++        }
++
++    case POINTER:
++        {
++            XimFrameType ret_type;
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++            {
++                dr.fi = FrameInstInit (it->template[1].data);
++                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
++            }
++            /*endif*/
++
++            ret_type = FrameInstGetNextType (d->fi, info);
++            if (ret_type == EOL)
++            {
++                it->cur_no++;
++                ret_type = IterGetNextType (it, info);
++            }
++            /*endif*/
++	    return ret_type;
++        }
++
++    default:
++	return (XimFrameType) NULL;
++    }
++    /*endswitch*/
++    return (XimFrameType) NULL;  /* This should never occur */
++}
++
++static XimFrameType IterPeekNextType (Iter it, XimFrameTypeInfo info)
++{
++    XimFrameType type = it->template->type;
++
++    if (!it->allow_expansion  &&  it->cur_no >= it->max_count)
++        return (EOL);
++    /*endif*/
++
++    switch (type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++        return type;
++
++    case BARRAY:
++        if (info)
++        {
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++                info->num = NO_VALUE;
++            else
++                info->num = d->num;
++            /*endif*/
++        }
++        /*endif*/
++        return BARRAY;
++
++    case ITER:
++        {
++            XimFrameType ret_type;
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++            {
++                dr.iter = IterInit (it->template + 1, NO_VALUE);
++                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
++            }
++            /*endif*/
++
++            ret_type = IterPeekNextType (d->iter, info);
++            if (ret_type == EOL)
++                ret_type = IterPeekNextType (it, info);
++            /*endif*/
++            return ret_type;
++        }
++
++    case POINTER:
++        {
++            XimFrameType ret_type;
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++            {
++                dr.fi = FrameInstInit (it->template[1].data);
++                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
++            }
++            /*endif*/
++
++            ret_type = FrameInstPeekNextType (d->fi, info);
++            if (ret_type == EOL)
++                ret_type = IterPeekNextType (it, info);
++            /*endif*/
++            return (ret_type);
++        }
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    /* Reaching here is a bug! */
++    return (XimFrameType) NULL;
++}
++
++static FmStatus IterSetSize (Iter it, int num)
++{
++    XimFrameType type;
++    register int i;
++
++    if (!it->allow_expansion  &&  it->max_count == 0)
++        return FmNoMoreData;
++    /*endif*/
++
++    type = it->template->type;
++    switch (type)
++    {
++    case BARRAY:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++
++            for (i = 0;  i < it->max_count;  i++)
++            {
++                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++                {
++                    dr.num = NO_VALUE;
++                    d = ChainMgrSetData (&it->cm, i, dr);
++                }
++                /*endif*/
++                if (d->num == NO_VALUE)
++                {
++                    d->num = num;
++                    return FmSuccess;
++                }
++                /*endif*/
++            }
++            /*endfor*/
++            if (it->allow_expansion)
++            {
++                ExtraDataRec dr;
++
++                dr.num = num;
++                ChainMgrSetData (&it->cm, it->max_count, dr);
++                it->max_count++;
++
++                return FmSuccess;
++            }
++            /*endif*/
++        }
++        return FmNoMoreData;
++
++    case ITER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++
++            for (i = 0;  i < it->max_count;  i++)
++            {
++                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++                {
++                    dr.iter = IterInit (it->template + 1, NO_VALUE);
++                    d = ChainMgrSetData (&it->cm, i, dr);
++                }
++                /*endif*/
++                if (IterSetSize (d->iter, num) == FmSuccess)
++                    return FmSuccess;
++                /*endif*/
++            }
++            /*endfor*/
++            if (it->allow_expansion)
++            {
++                ExtraDataRec dr;
++
++                dr.iter = IterInit (it->template + 1, NO_VALUE);
++                ChainMgrSetData (&it->cm, it->max_count, dr);
++                it->max_count++;
++
++                if (IterSetSize(dr.iter, num) == FmSuccess)
++                    return FmSuccess;
++                /*endif*/
++            }
++            /*endif*/
++        }
++        return FmNoMoreData;
++
++    case POINTER:
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++
++            for (i = 0;  i < it->max_count;  i++)
++            {
++                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++                {
++                    dr.fi = FrameInstInit (it->template[1].data);
++                    d = ChainMgrSetData (&it->cm, i, dr);
++                }
++                /*endif*/
++                if (FrameInstSetSize (d->fi, num) == FmSuccess)
++                    return FmSuccess;
++                /*endif*/
++            }
++            /*endfor*/
++            if (it->allow_expansion)
++            {
++                ExtraDataRec dr;
++
++                dr.fi = FrameInstInit (it->template[1].data);
++                ChainMgrSetData (&it->cm, it->max_count, dr);
++                it->max_count++;
++
++                if (FrameInstSetSize (dr.fi, num) == FmSuccess)
++                    return FmSuccess;
++                /*endif*/
++            }
++            /*endif*/
++        }
++        return FmNoMoreData;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    return FmNoMoreData;
++}
++
++static int IterGetSize (Iter it)
++{
++    register int i;
++    ExtraData d;
++    ExtraDataRec dr;
++
++    if (it->cur_no >= it->max_count)
++        return NO_VALID_FIELD;
++    /*endif*/
++
++    switch (it->template->type)
++    {
++    case BARRAY:
++        if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
++            return NO_VALUE;
++        /*endif*/
++        return d->num;
++
++    case ITER:
++        for (i = it->cur_no; i < it->max_count; i++)
++        {
++            int ret_size;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++            {
++                dr.iter = IterInit (it->template + 1, NO_VALUE);
++                d = ChainMgrSetData (&it->cm, i, dr);
++            }
++            /*endif*/
++            ret_size = IterGetSize (d->iter);
++            if (ret_size != NO_VALID_FIELD)
++                return ret_size;
++            /*endif*/
++        }
++        /*endfor*/
++        return NO_VALID_FIELD;
++
++    case POINTER:
++        for (i = it->cur_no;  i < it->max_count;  i++)
++        {
++            int ret_size;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit (it->template[1].data);
++                d = ChainMgrSetData (&it->cm, i, dr);
++            }
++            /*endif*/
++            ret_size = FrameInstGetSize (d->fi);
++            if (ret_size != NO_VALID_FIELD)
++                return ret_size;
++            /*endif*/
++        }
++        /*endfor*/
++        return NO_VALID_FIELD;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    return NO_VALID_FIELD;
++}
++
++static FmStatus IterSetIterCount (Iter it, int num)
++{
++    register int i;
++
++    if (it->allow_expansion)
++    {
++        it->max_count = num;
++        it->allow_expansion = False;
++        return FmSuccess;
++    }
++    /*endif*/
++
++    if (it->max_count == 0)
++        return FmNoMoreData;
++    /*endif*/
++
++    switch (it->template->type)
++    {
++    case ITER:
++        for (i = 0;  i < it->max_count;  i++)
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData(&it->cm, i)) == NULL)
++            {
++                dr.iter = IterInit(it->template + 1, num);
++                (void)ChainMgrSetData(&it->cm, i, dr);
++                return FmSuccess;
++            }
++            /*endif*/
++            if (IterSetIterCount(d->iter, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++        }
++        /*endfor*/
++        if (it->allow_expansion)
++        {
++            ExtraDataRec dr;
++
++            dr.iter = IterInit (it->template + 1, num);
++            ChainMgrSetData (&it->cm, it->max_count, dr);
++            it->max_count++;
++
++            return FmSuccess;
++        }
++        /*endif*/
++        break;
++
++    case POINTER:
++        for (i = 0;  i < it->max_count;  i++)
++        {
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit (it->template[1].data);
++                d = ChainMgrSetData (&it->cm, i, dr);
++            }
++            /*endif*/
++            if (FrameInstSetIterCount (d->fi, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++        }
++        /*endfor*/
++        if (it->allow_expansion)
++        {
++            ExtraDataRec dr;
++
++            dr.fi = FrameInstInit (it->template[1].data);
++            ChainMgrSetData (&it->cm, it->max_count, dr);
++            it->max_count++;
++
++            if (FrameInstSetIterCount (dr.fi, num) == FmSuccess)
++                return FmSuccess;
++            /*endif*/
++        }
++        /*endif*/
++        break;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    return FmNoMoreData;
++}
++
++static int IterGetTotalSize (Iter it)
++{
++    register int size, i;
++    XimFrameType type;
++
++    if (it->allow_expansion)
++        return NO_VALUE;
++    /*endif*/
++    if (it->max_count == 0)
++        return 0;
++    /*endif*/
++
++    size = 0;
++    type = it->template->type;
++
++    switch (type)
++    {
++    case BIT8:
++        size = it->max_count;
++        break;
++
++    case BIT16:
++        size = it->max_count*2;
++        break;
++
++    case BIT32:
++        size = it->max_count*4;
++        break;
++
++    case BIT64:
++        size = it->max_count*8;
++        break;
++
++    case BARRAY:
++        for (i = 0;  i < it->max_count;  i++)
++        {
++            register int num;
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++                return  NO_VALUE;
++            /*endif*/
++            if ((num = d->num) == NO_VALUE)
++                return  NO_VALUE;
++            /*endif*/
++            size += num;
++        }
++        /*endfor*/
++        break;
++
++    case ITER:
++        for (i = 0;  i < it->max_count;  i++)
++        {
++            register int num;
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++                return  NO_VALUE;
++            /*endif*/
++            if ((num = IterGetTotalSize (d->iter)) == NO_VALUE)
++                return  NO_VALUE;
++            /*endif*/
++            size += num;
++        }
++        /*endfor*/
++        break;
++
++    case POINTER:
++        for (i = 0;  i < it->max_count;  i++)
++        {
++            register int num;
++            ExtraData d;
++            ExtraDataRec dr;
++
++            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
++            {
++                dr.fi = FrameInstInit (it->template[1].data);
++                d = ChainMgrSetData (&it->cm, i, dr);
++            }
++            /*endif*/
++            if ((num = FrameInstGetTotalSize (d->fi)) == NO_VALUE)
++                return NO_VALUE;
++            /*endif*/
++            size += num;
++        }
++        /*endfor*/
++        break;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    return  size;
++}
++
++static void IterReset (Iter it)
++{
++    ChainIterRec ci;
++    int count;
++    ExtraDataRec d;
++
++    switch (it->template->type)
++    {
++    case ITER:
++        ChainIterInit (&ci, &it->cm);
++        while (ChainIterGetNext (&ci, &count, &d))
++            IterReset (d.iter);
++        /*endwhile*/
++        ChainIterFree (&ci);
++        break;
++
++    case POINTER:
++        ChainIterInit (&ci, &it->cm);
++        while (ChainIterGetNext (&ci, &count, &d))
++            FrameInstReset (d.fi);
++        /*endwhile*/
++        ChainIterFree (&ci);
++        break;
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    it->cur_no = 0;
++}
++
++static void IterSetStartWatch (Iter it,
++                               IterStartWatchProc proc,
++                               void *client_data)
++{
++    it->start_watch_proc = proc;
++    it->client_data = client_data;
++}
++
++static ExtraData ChainMgrSetData (ChainMgr cm,
++                                  int frame_no,
++                                  ExtraDataRec data)
++{
++    Chain cur = (Chain) Xmalloc (sizeof (ChainRec));
++
++    cur->frame_no = frame_no;
++    cur->d = data;
++    cur->next = NULL;
++
++    if (cm->top == NULL)
++    {
++        cm->top = cm->tail = cur;
++    }
++    else
++    {
++        cm->tail->next = cur;
++        cm->tail = cur;
++    }
++    /*endif*/
++    return &cur->d;
++}
++
++static ExtraData ChainMgrGetExtraData (ChainMgr cm, int frame_no)
++{
++    Chain cur;
++
++    cur = cm->top;
++
++    while (cur)
++    {
++        if (cur->frame_no == frame_no)
++            return &cur->d;
++        /*endif*/
++        cur = cur->next;
++    }
++    /*endwhile*/
++    return NULL;
++}
++
++static Bool ChainIterGetNext (ChainIter ci, int *frame_no, ExtraData d)
++{
++    if (ci->cur == NULL)
++        return False;
++    /*endif*/
++
++    *frame_no = ci->cur->frame_no;
++    *d = ci->cur->d;
++
++    ci->cur = ci->cur->next;
++
++    return True;
++}
++
++static int _FrameInstIncrement (XimFrame frame, int count)
++{
++    XimFrameType type;
++
++    type = frame[count].type;
++    type &= ~COUNTER_MASK;
++
++    switch (type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++    case BARRAY:
++    case PADDING:
++        return count + 1;
++
++    case POINTER:
++        return count + 2;
++
++    case ITER:
++        return _FrameInstIncrement (frame, count + 1);
++    default:
++	break;
++    }
++    /*endswitch*/
++    return - 1;    /* Error */
++}
++
++static int _FrameInstDecrement (XimFrame frame, int count)
++{
++    register int i;
++    XimFrameType type;
++
++    if (count == 0)
++        return - 1;    /* cannot decrement */
++    /*endif*/
++
++    if (count == 1)
++        return 0;     /* BOGUS - It should check the contents of data */
++    /*endif*/
++
++    type = frame[count - 2].type;
++    type &= ~COUNTER_MASK;
++
++    switch (type)
++    {
++    case BIT8:
++    case BIT16:
++    case BIT32:
++    case BIT64:
++    case BARRAY:
++    case PADDING:
++    case PTR_ITEM:
++        return count - 1;
++
++    case POINTER:
++    case ITER:
++        i = count - 3;
++        while (i >= 0)
++        {
++            if (frame[i].type != ITER)
++                return i + 1;
++            /*endif*/
++            i--;
++        }
++        /*endwhile*/
++        return 0;
++    default:
++	break;
++    }
++    /*enswitch*/
++    return - 1;    /* Error */
++}
++
++static int _FrameInstGetItemSize (FrameInst fi, int cur_no)
++{
++    XimFrameType type;
++
++    type = fi->template[cur_no].type;
++    type &= ~COUNTER_MASK;
++
++    switch (type)
++    {
++    case BIT8:
++        return 1;
++
++    case BIT16:
++        return 2;
++
++    case BIT32:
++        return 4;
++
++    case BIT64:
++        return 8;
++
++    case BARRAY:
++        {
++            ExtraData d;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
++                return NO_VALUE;
++            /*endif*/
++            if (d->num == NO_VALUE)
++                return NO_VALUE;
++            /*endif*/
++            return d->num;
++        }
++
++    case PADDING:
++        {
++            register int unit;
++            register int number;
++            register int size;
++            register int i;
++
++            unit = _UNIT ((long) fi->template[cur_no].data);
++            number = _NUMBER ((long) fi->template[cur_no].data);
++
++            i = cur_no;
++            size = 0;
++            while (number > 0)
++            {
++                i = _FrameInstDecrement (fi->template, i);
++                size += _FrameInstGetItemSize (fi, i);
++                number--;
++            }
++            /*endwhile*/
++            size = (unit - (size%unit))%unit;
++            return size;
++        }
++
++    case ITER:
++        {
++            ExtraData d;
++            int sub_size;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
++                return NO_VALUE;
++            /*endif*/
++            sub_size = IterGetTotalSize (d->iter);
++            if (sub_size == NO_VALUE)
++                return NO_VALUE;
++            /*endif*/
++            return sub_size;
++        }
++
++    case POINTER:
++        {
++            ExtraData d;
++            int sub_size;
++
++            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
++                return NO_VALUE;
++            /*endif*/
++            sub_size = FrameInstGetTotalSize (d->fi);
++            if (sub_size == NO_VALUE)
++                return NO_VALUE;
++            /*endif*/
++            return sub_size;
++        }
++
++    default:
++	break;
++    }
++    /*endswitch*/
++    return NO_VALUE;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.h
+new file mode 100644
+index 0000000..ce7ed50
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/FrameMgr.h
+@@ -0,0 +1,131 @@
++/******************************************************************
++Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
++
++                        All Rights Reserved
++
++Permission to use, copy, modify, and distribute this software and its
++documentation for any purpose and without fee is hereby granted,
++provided that the above copyright notice appear in all copies and that
++both that copyright notice and this permission notice appear in
++supporting documentation, and that the names of Digital or MIT not be
++used in advertising or publicity pertaining to distribution of the
++software without specific, written prior permission.
++
++DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
++ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
++ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
++WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
++ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
++SOFTWARE.
++
++  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
++                             miyamoto@jrd.dec.com
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef FRAMEMGR_H
++#define FRAMEMGR_H
++
++#include <X11/Xmd.h>
++#include <X11/Xlib.h>
++#include <stdio.h>
++
++#if defined(VAXC) && !defined(__DECC)
++#define xim_externalref globalref
++#define xim_externaldef globaldef
++#else
++#define xim_externalref extern
++#define xim_externaldef
++#endif
++
++/* Definitions for FrameMgr */
++
++#define COUNTER_MASK 0x10
++
++typedef enum
++{
++    BIT8     = 0x1,       /* {CARD8* | INT8*}   */
++    BIT16    = 0x2,       /* {CARD16* | INT16*} */
++    BIT32    = 0x3,       /* {CARD32* | INT32*} */
++    BIT64    = 0x4,	  /* {CARD64* | INT64*} */
++    BARRAY   = 0x5,       /* int*, void*        */
++    ITER     = 0x6,       /* int*               */
++    POINTER  = 0x7,       /* specifies next item is a PTR_ITEM */
++    PTR_ITEM = 0x8,       /* specifies the item has a pointer */
++    /* BOGUS - POINTER and PTR_ITEM
++     *   In the current implementation, PTR_ITEM should be lead by
++     *   POINTER.  But actually, it's just redundant logically.  Someone
++     *   may remove this redundancy and POINTER from the enum member but he
++     *   should also modify the logic in FrameMgr program.
++     */
++    PADDING  = 0x9,       /* specifies that a padding is needed.
++		           * This requires extra data in data field.
++		           */
++    EOL      = 0xA,       /* specifies the end of list */
++
++    COUNTER_BIT8  = COUNTER_MASK | 0x1,
++    COUNTER_BIT16 = COUNTER_MASK | 0x2,
++    COUNTER_BIT32 = COUNTER_MASK | 0x3,
++    COUNTER_BIT64 = COUNTER_MASK | 0x4
++} XimFrameType;
++
++/* Convenient macro */
++#define _FRAME(a) {a, NULL}
++#define _PTR(p)   {PTR_ITEM, (void *)p}
++/* PADDING's usage of data field
++ * B15-B8  : Shows the number of effective items.
++ * B7-B0   : Shows padding unit.  ex) 04 shows 4 unit padding.
++ */
++#define _PAD2(n)   {PADDING, (void*)((n)<<8|2)}
++#define _PAD4(n)   {PADDING, (void*)((n)<<8|4)}
++
++#define FmCounterByte 0
++#define FmCounterNumber 1
++
++#define _BYTE_COUNTER(type, offset) \
++               {(COUNTER_MASK|type), (void*)((offset)<<8|FmCounterByte)}
++
++#define _NUMBER_COUNTER(type, offset) \
++               {(COUNTER_MASK|type), (void*)((offset)<<8|FmCounterNumber)}
++
++typedef struct _XimFrame
++{
++    XimFrameType type;
++    void* data;       /* For PTR_ITEM and PADDING */
++} XimFrameRec, *XimFrame;
++
++typedef enum
++{
++    FmSuccess,
++    FmEOD,
++    FmInvalidCall,
++    FmBufExist,
++    FmCannotCalc,
++    FmNoMoreData
++} FmStatus;
++
++typedef struct _FrameMgr *FrameMgr;
++
++FrameMgr FrameMgrInit(XimFrame frame, char* area, Bool byte_swap);
++void FrameMgrInitWithData(FrameMgr fm, XimFrame frame, void* area,
++			  Bool byte_swap);
++void FrameMgrFree(FrameMgr fm);
++FmStatus FrameMgrSetBuffer(FrameMgr, void*);
++FmStatus _FrameMgrPutToken(FrameMgr, void*, int);
++FmStatus _FrameMgrGetToken(FrameMgr, void*, int);
++FmStatus FrameMgrSetSize(FrameMgr, int);
++FmStatus FrameMgrSetIterCount(FrameMgr, int);
++FmStatus FrameMgrSetTotalSize(FrameMgr, int);
++int FrameMgrGetTotalSize(FrameMgr);
++int FrameMgrGetSize(FrameMgr);
++FmStatus FrameMgrSkipToken(FrameMgr, int);
++void FrameMgrReset(FrameMgr);
++Bool FrameMgrIsIterLoopEnd(FrameMgr, FmStatus*);
++
++#define FrameMgrPutToken(fm, obj) _FrameMgrPutToken((fm), &(obj), sizeof(obj))
++#define FrameMgrGetToken(fm, obj) _FrameMgrGetToken((fm), &(obj), sizeof(obj))
++
++#endif /* FRAMEMGR_H */
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMConn.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMConn.c
+new file mode 100644
+index 0000000..44cd9e8
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMConn.c
+@@ -0,0 +1,176 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include <stdlib.h>
++#include <string.h>
++#include "../include/IMdkit.h"
++#include <stdarg.h>
++
++#define Va_start(a,b) va_start(a,b)
++
++static void _IMCountVaList(va_list var, int *total_count)
++{
++    char *attr;
++
++    *total_count = 0;
++
++    for (attr = va_arg (var, char*);  attr;  attr = va_arg (var, char*))
++    {
++	(void)va_arg (var, XIMArg *);
++	++(*total_count);
++    }
++    /*endfor*/
++}
++
++static void _IMVaToNestedList(va_list var, int max_count, XIMArg **args_return)
++{
++    XIMArg *args;
++    char   *attr;
++
++    if (max_count <= 0)
++    {
++	*args_return = (XIMArg *) NULL;
++	return;
++    }
++    /*endif*/
++
++    args = (XIMArg *) malloc ((unsigned) (max_count + 1)*sizeof (XIMArg));
++    *args_return = args;
++    if (!args)
++        return;
++    /*endif*/
++
++    for (attr = va_arg (var, char*);  attr;  attr = va_arg (var, char *))
++    {
++	args->name = attr;
++	args->value = va_arg (var, XPointer);
++	args++;
++    }
++    /*endfor*/
++    args->name = (char*)NULL;
++}
++
++static char *_FindModifiers (XIMArg *args)
++{
++    char *modifiers;
++
++    while (args->name)
++    {
++	if (strcmp (args->name, IMModifiers) == 0)
++	{
++	    modifiers = args->value;
++	    return modifiers;
++	}
++	else
++	{
++	    args++;
++	}
++	/*endif*/
++    }
++    /*endwhile*/
++    return NULL;
++}
++
++XIMS _GetIMS (char *modifiers)
++{
++    XIMS ims;
++    extern IMMethodsRec Xi18n_im_methods;
++
++    if ((ims = (XIMS) malloc (sizeof (XIMProtocolRec))) == (XIMS) NULL)
++	return ((XIMS) NULL);
++    /*endif*/
++    memset ((void *) ims, 0, sizeof (XIMProtocolRec));
++
++    if (modifiers == NULL
++	||
++	modifiers[0] == '\0'
++	||
++	strcmp (modifiers, "Xi18n") == 0)
++    {
++	ims->methods = &Xi18n_im_methods;
++	return ims;
++    }
++    /*endif*/
++    XFree (ims);
++    return (XIMS) NULL;
++}
++
++XIMS IMOpenIM (Display *display, ...)
++{
++    va_list var;
++    int total_count;
++    XIMArg *args;
++    XIMS ims;
++    char *modifiers;
++    Status ret;
++
++    Va_start (var, display);
++    _IMCountVaList (var, &total_count);
++    va_end (var);
++
++    Va_start (var, display);
++    _IMVaToNestedList (var, total_count, &args);
++    va_end (var);
++
++    modifiers = _FindModifiers (args);
++
++    ims = _GetIMS (modifiers);
++    if (ims == (XIMS) NULL)
++        return (XIMS) NULL;
++    /*endif*/
++
++    ims->core.display = display;
++
++    ims->protocol = (*ims->methods->setup) (display, args);
++    XFree (args);
++    if (ims->protocol == (void *) NULL)
++    {
++	XFree (ims);
++	return (XIMS) NULL;
++    }
++    /*endif*/
++    ret = (ims->methods->openIM) (ims);
++    if (ret == False)
++    {
++	XFree (ims);
++	return (XIMS) NULL;
++    }
++    /*endif*/
++    return (XIMS) ims;
++}
++
++Status IMCloseIM (XIMS ims)
++{
++    (ims->methods->closeIM) (ims);
++    XFree (ims);
++    return True;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMMethod.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMMethod.c
+new file mode 100644
+index 0000000..ff3fb2a
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/IMMethod.c
+@@ -0,0 +1,65 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include "../include/IMdkit.h"
++
++/* Public Function */
++void IMForwardEvent (XIMS ims, XPointer call_data)
++{
++    (ims->methods->forwardEvent) (ims, call_data);
++}
++
++void IMCommitString (XIMS ims, XPointer call_data)
++{
++    (ims->methods->commitString) (ims, call_data);
++}
++
++int IMCallCallback (XIMS ims, XPointer call_data)
++{
++    return (ims->methods->callCallback) (ims, call_data);
++}
++
++int IMPreeditStart (XIMS ims, XPointer call_data)
++{
++    return (ims->methods->preeditStart) (ims, call_data);
++}
++
++int IMPreeditEnd (XIMS ims, XPointer call_data)
++{
++    return (ims->methods->preeditEnd) (ims, call_data);
++}
++
++int IMSyncXlib(XIMS ims, XPointer call_data)
++{
++    ims->sync = True;
++    return (ims->methods->syncXlib) (ims, call_data);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/Xi18nX.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/Xi18nX.h
+new file mode 100644
+index 0000000..ff91b1a
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/Xi18nX.h
+@@ -0,0 +1,52 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef _Xi18nTrX_h
++#define _Xi18nTrX_h
++
++#define _XIM_PROTOCOL           "_XIM_PROTOCOL"
++#define _XIM_XCONNECT           "_XIM_XCONNECT"
++
++#define XCM_DATA_LIMIT		20
++
++typedef struct _XClient
++{
++    Window	client_win;	/* client window */
++    Window	accept_win;	/* accept window */
++} XClient;
++
++typedef struct
++{
++    Atom	xim_request;
++    Atom	connect_request;
++} XSpecRec;
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/XimFunc.h b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/XimFunc.h
+new file mode 100644
+index 0000000..a9f4a04
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/XimFunc.h
+@@ -0,0 +1,72 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#ifndef _XimFunc_h
++#define _XimFunc_h
++
++/* i18nAttr.c */
++void _Xi18nInitAttrList (Xi18n i18n_core);
++void _Xi18nInitExtension(Xi18n i18n_core);
++
++/* i18nClbk.c */
++int _Xi18nGeometryCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nPreeditStartCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nPreeditDrawCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nPreeditCaretCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nPreeditDoneCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nStatusStartCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nStatusDoneCallback (XIMS ims, IMProtocol *call_data);
++int _Xi18nStringConversionCallback (XIMS ims, IMProtocol *call_data);
++
++/* i18nIc.c */
++void _Xi18nChangeIC (XIMS ims, IMProtocol *call_data, unsigned char *p,
++                     int create_flag);
++void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p);
++
++/* i18nUtil.c */
++int _Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id);
++Xi18nClient *_Xi18nNewClient(Xi18n i18n_core);
++Xi18nClient *_Xi18nFindClient (Xi18n i18n_core, CARD16 connect_id);
++void _Xi18nDeleteClient (Xi18n i18n_core, CARD16 connect_id);
++void _Xi18nSendMessage (XIMS ims, CARD16 connect_id, CARD8 major_opcode,
++                        CARD8 minor_opcode, unsigned char *data, long length);
++void _Xi18nSendTriggerKey (XIMS ims, CARD16 connect_id);
++void _Xi18nSetEventMask (XIMS ims, CARD16 connect_id, CARD16 im_id,
++                         CARD16 ic_id, CARD32 forward_mask, CARD32 sync_mask);
++
++/* Xlib internal */
++void _XRegisterFilterByType(Display*, Window, int, int,
++		Bool (*filter)(Display*, Window, XEvent*, XPointer), XPointer);
++void _XUnregisterFilter(Display*, Window,
++		Bool (*filter)(Display*, Window, XEvent*, XPointer), XPointer);
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nAttr.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nAttr.c
+new file mode 100644
+index 0000000..1647639
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nAttr.c
+@@ -0,0 +1,175 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include <X11/Xresource.h>
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "XimFunc.h"
++
++typedef struct
++{
++    char *name;
++    CARD16 type;
++} IMListOfAttr;
++
++typedef struct
++{
++    char *name;
++    CARD8 major_opcode;
++    CARD8 minor_opcode;
++} IMExtList;
++
++IMListOfAttr Default_IMattr[] =
++{
++    {XNQueryInputStyle,   XimType_XIMStyles},
++/*    {XNQueryIMValuesList, XimType_XIMValuesList},	*/
++    {(char *) NULL, (CARD16) 0}
++};
++
++IMListOfAttr Default_ICattr[] =
++{
++    {XNInputStyle,              XimType_CARD32},
++    {XNClientWindow,            XimType_Window},
++    {XNFocusWindow,             XimType_Window},
++    {XNFilterEvents,            XimType_CARD32},
++    {XNPreeditAttributes,       XimType_NEST},
++    {XNStatusAttributes,        XimType_NEST},
++    {XNFontSet,                 XimType_XFontSet},
++    {XNArea,                    XimType_XRectangle},
++    {XNAreaNeeded,              XimType_XRectangle},
++    {XNColormap,                XimType_CARD32},
++    {XNStdColormap,             XimType_CARD32},
++    {XNForeground,              XimType_CARD32},
++    {XNBackground,              XimType_CARD32},
++    {XNBackgroundPixmap,        XimType_CARD32},
++    {XNSpotLocation,            XimType_XPoint},
++    {XNLineSpace,               XimType_CARD32},
++    {XNPreeditState,            XimType_CARD32},
++    {XNSeparatorofNestedList,   XimType_SeparatorOfNestedList},
++    {(char *) NULL, 0}
++};
++
++IMExtList Default_Extension[] =
++{
++    {"XIM_EXT_MOVE", XIM_EXTENSION, XIM_EXT_MOVE},
++    {"XIM_EXT_SET_EVENT_MASK", XIM_EXTENSION, XIM_EXT_SET_EVENT_MASK},
++    {"XIM_EXT_FORWARD_KEYEVENT", XIM_EXTENSION, XIM_EXT_FORWARD_KEYEVENT},
++    {(char *) NULL, 0, 0}
++};
++
++static void CountAttrList(IMListOfAttr *attr, int *total_count)
++{
++    *total_count = 0;
++
++    while (attr->name != NULL)
++    {
++        attr++;
++        ++(*total_count);
++    }
++}
++
++static XIMAttr *CreateAttrList (Xi18n i18n_core,
++                                IMListOfAttr *attr,
++                                int *total_count)
++{
++    XIMAttr *args, *p;
++    unsigned int buf_size;
++
++    CountAttrList(attr, total_count);
++
++    buf_size = (unsigned) (*total_count + 1)*sizeof (XIMAttr);
++    args = (XIMAttr *) malloc (buf_size);
++    if (!args)
++        return (XIMAttr *) NULL;
++    /*endif*/
++    memset (args, 0, buf_size);
++
++    for (p = args;  attr->name != NULL;  attr++, p++)
++    {
++        p->name = attr->name;
++        p->length = strlen (attr->name);
++        p->type = (CARD16) attr->type;
++        p->attribute_id = XrmStringToQuark (p->name);
++        if (strcmp (p->name, XNPreeditAttributes) == 0)
++            i18n_core->address.preeditAttr_id = p->attribute_id;
++        else if (strcmp (p->name, XNStatusAttributes) == 0)
++            i18n_core->address.statusAttr_id = p->attribute_id;
++        else if (strcmp (p->name, XNSeparatorofNestedList) == 0)
++            i18n_core->address.separatorAttr_id = p->attribute_id;
++        /*endif*/
++    }
++    /*endfor*/
++    p->name = (char *) NULL;
++
++    return args;
++}
++
++void _Xi18nInitAttrList (Xi18n i18n_core)
++{
++    XIMAttr *args;
++    int	total_count;
++
++    /* init IMAttr list */
++    if (i18n_core->address.xim_attr)
++        XFree ((char *)i18n_core->address.xim_attr);
++    /*endif*/
++    args = CreateAttrList (i18n_core, Default_IMattr, &total_count);
++
++    i18n_core->address.im_attr_num = total_count;
++    i18n_core->address.xim_attr = (XIMAttr *)args;
++
++    /* init ICAttr list */
++    if (i18n_core->address.xic_attr)
++        XFree ((char *) i18n_core->address.xic_attr);
++    /*endif*/
++    args = CreateAttrList (i18n_core, Default_ICattr, &total_count);
++
++    i18n_core->address.ic_attr_num = total_count;
++    i18n_core->address.xic_attr = (XICAttr *) args;
++}
++
++void _Xi18nInitExtension(Xi18n i18n_core)
++{
++    register int i;
++    IMExtList *extensions = (IMExtList *) Default_Extension;
++    XIMExt *ext_list = (XIMExt *) i18n_core->address.extension;
++
++    for (i = 0;  extensions->name;  i++, ext_list++, extensions++)
++    {
++        ext_list->major_opcode = extensions->major_opcode;
++        ext_list->minor_opcode = extensions->minor_opcode;
++        ext_list->name = extensions->name;
++        ext_list->length = strlen(ext_list->name);
++    }
++    /*endfor*/
++    i18n_core->address.ext_num = i;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nClbk.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nClbk.c
+new file mode 100644
+index 0000000..887d769
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nClbk.c
+@@ -0,0 +1,513 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "FrameMgr.h"
++#include "XimFunc.h"
++
++int _Xi18nGeometryCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec geometry_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMGeometryCBStruct *geometry_CB =
++        (IMGeometryCBStruct *) &call_data->geometry_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (geometry_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, geometry_CB->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_GEOMETRY,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_GEOMETRY is an asyncronous protocol,
++       so return immediately. */
++    return True;
++}
++
++int _Xi18nPreeditStartCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_start_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct*) &call_data->preedit_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (preedit_start_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, preedit_CB->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_PREEDIT_START,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    return True;
++}
++
++int _Xi18nPreeditDrawCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_draw_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct *) &call_data->preedit_callback;
++    XIMPreeditDrawCallbackStruct *draw =
++        (XIMPreeditDrawCallbackStruct *) &preedit_CB->todo.draw;
++    CARD16 connect_id = call_data->any.connect_id;
++    register int feedback_count;
++    register int i;
++    BITMASK32 status = 0x0;
++
++    if (draw->text->length == 0)
++        status = 0x00000001;
++    else if (draw->text->feedback[0] == 0)
++        status = 0x00000002;
++    /*endif*/
++
++    fm = FrameMgrInit (preedit_draw_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set length of preedit string */
++    FrameMgrSetSize (fm, draw->text->length);
++
++    /* set iteration count for list of feedback */
++    for (i = 0;  draw->text->feedback[i] != 0;  i++)
++        ;
++    /*endfor*/
++    feedback_count = i;
++    FrameMgrSetIterCount (fm, feedback_count);
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, preedit_CB->icid);
++    FrameMgrPutToken (fm, draw->caret);
++    FrameMgrPutToken (fm, draw->chg_first);
++    FrameMgrPutToken (fm, draw->chg_length);
++    FrameMgrPutToken (fm, status);
++    FrameMgrPutToken (fm, draw->text->length);
++    FrameMgrPutToken (fm, draw->text->string);
++    for (i = 0;  i < feedback_count;  i++)
++        FrameMgrPutToken (fm, draw->text->feedback[i]);
++    /*endfor*/
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_PREEDIT_DRAW,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_PREEDIT_DRAW is an asyncronous protocol, so return immediately. */
++    return True;
++}
++
++int _Xi18nPreeditCaretCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_caret_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct*) &call_data->preedit_callback;
++    XIMPreeditCaretCallbackStruct *caret =
++        (XIMPreeditCaretCallbackStruct *) &preedit_CB->todo.caret;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (preedit_caret_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, preedit_CB->icid);
++    FrameMgrPutToken (fm, caret->position);
++    FrameMgrPutToken (fm, caret->direction);
++    FrameMgrPutToken (fm, caret->style);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_PREEDIT_CARET,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    return True;
++}
++
++int _Xi18nPreeditDoneCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_done_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct *) &call_data->preedit_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (preedit_done_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, preedit_CB->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_PREEDIT_DONE,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_PREEDIT_DONE is an asyncronous protocol, so return immediately. */
++    return True;
++}
++
++int _Xi18nStatusStartCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec status_start_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMStatusCBStruct *status_CB =
++        (IMStatusCBStruct*) &call_data->status_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (status_start_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, status_CB->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_STATUS_START,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_STATUS_START is an asyncronous protocol, so return immediately. */
++    return True;
++}
++
++int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm = (FrameMgr)0;
++    extern XimFrameRec status_draw_text_fr[];
++    extern XimFrameRec status_draw_bitmap_fr[];
++    register int total_size = 0;
++    unsigned char *reply = NULL;
++    IMStatusCBStruct *status_CB =
++        (IMStatusCBStruct *) &call_data->status_callback;
++    XIMStatusDrawCallbackStruct *draw =
++        (XIMStatusDrawCallbackStruct *) &status_CB->todo.draw;
++    CARD16 connect_id = call_data->any.connect_id;
++    register int feedback_count;
++    register int i;
++    BITMASK32 status = 0x0;
++
++    switch (draw->type)
++    {
++    case XIMTextType:
++        fm = FrameMgrInit (status_draw_text_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++
++        if (draw->data.text->length == 0)
++            status = 0x00000001;
++        else if (draw->data.text->feedback[0] == 0)
++            status = 0x00000002;
++        /*endif*/
++
++        /* set length of status string */
++        FrameMgrSetSize(fm, draw->data.text->length);
++        /* set iteration count for list of feedback */
++        for (i = 0;  draw->data.text->feedback[i] != 0;  i++)
++            ;
++        /*endfor*/
++        feedback_count = i;
++        FrameMgrSetIterCount (fm, feedback_count);
++
++        total_size = FrameMgrGetTotalSize (fm);
++        reply = (unsigned char *) malloc (total_size);
++        if (!reply)
++        {
++            _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++            return False;
++        }
++        /*endif*/
++        memset (reply, 0, total_size);
++        FrameMgrSetBuffer (fm, reply);
++
++        FrameMgrPutToken (fm, connect_id);
++        FrameMgrPutToken (fm, status_CB->icid);
++        FrameMgrPutToken (fm, draw->type);
++        FrameMgrPutToken (fm, status);
++        FrameMgrPutToken (fm, draw->data.text->length);
++        FrameMgrPutToken (fm, draw->data.text->string);
++        for (i = 0;  i < feedback_count;  i++)
++            FrameMgrPutToken (fm, draw->data.text->feedback[i]);
++        /*endfor*/
++        break;
++
++    case XIMBitmapType:
++        fm = FrameMgrInit (status_draw_bitmap_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++
++        total_size = FrameMgrGetTotalSize (fm);
++        reply = (unsigned char *) malloc (total_size);
++        if (!reply)
++        {
++            _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++            return False;
++        }
++        /*endif*/
++        memset (reply, 0, total_size);
++        FrameMgrSetBuffer (fm, reply);
++
++        FrameMgrPutToken (fm, connect_id);
++        FrameMgrPutToken (fm, status_CB->icid);
++        FrameMgrPutToken (fm, draw->data.bitmap);
++        break;
++    }
++    /*endswitch*/
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_STATUS_DRAW,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_STATUS_DRAW is an asyncronous protocol, so return immediately. */
++    return True;
++}
++
++int _Xi18nStatusDoneCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec status_done_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMStatusCBStruct *status_CB =
++        (IMStatusCBStruct *) &call_data->status_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (status_done_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, status_CB->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_STATUS_DONE,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_STATUS_DONE is an asyncronous protocol, so return immediately. */
++    return True;
++}
++
++int _Xi18nStringConversionCallback (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec str_conversion_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMStrConvCBStruct *call_back =
++        (IMStrConvCBStruct *) &call_data->strconv_callback;
++    XIMStringConversionCallbackStruct *strconv =
++        (XIMStringConversionCallbackStruct *) &call_back->strconv;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (str_conversion_fr,
++                       NULL,
++                      _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, connect_id);
++    FrameMgrPutToken (fm, call_back->icid);
++    FrameMgrPutToken (fm, strconv->position);
++    FrameMgrPutToken (fm, strconv->direction);
++    FrameMgrPutToken (fm, strconv->operation);
++
++    _Xi18nSendMessage (ims, connect_id,
++                       XIM_STR_CONVERSION,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    /* XIM_STR_CONVERSION is a syncronous protocol,
++       so should wait here for XIM_STR_CONVERSION_REPLY. */
++    if (i18n_core->methods.wait (ims,
++                                 connect_id,
++                                 XIM_STR_CONVERSION_REPLY,
++                                 0) == False)
++    {
++        return False;
++    }
++    /*endif*/
++    return True;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIMProto.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIMProto.c
+new file mode 100644
+index 0000000..618da9d
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIMProto.c
+@@ -0,0 +1,773 @@
++/******************************************************************
++Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
++Copyright 1993, 1994 by Hewlett-Packard Company
++
++Copyright 1994, 1995 by Sun Microsystems, Inc.
++
++                        All Rights Reserved
++
++Permission to use, copy, modify, and distribute this software and its
++documentation for any purpose and without fee is hereby granted,
++provided that the above copyright notice appear in all copies and that
++both that copyright notice and this permission notice appear in
++supporting documentation, and that the names of Digital or MIT not be
++used in advertising or publicity pertaining to distribution of the
++software without specific, written prior permission.
++
++DIGITAL AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL WARRANTIES WITH REGARD
++TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
++FITNESS, IN NO EVENT SHALL DIGITAL AND HEWLETT-PACKARD COMPANY BE LIABLE
++FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
++CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
++                             miyamoto@jrd.dec.com
++	  Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++/* Protocol Packet frames */
++
++#include "FrameMgr.h"
++
++/* Data type definitions */
++
++static XimFrameRec ximattr_fr[] =
++{
++    _FRAME(BIT16), 		/* attribute ID */
++    _FRAME(BIT16), 		/* type of the value */
++    _FRAME(BIT16), 		/* length of im-attribute */
++    _FRAME(BARRAY), 		/* im-attribute */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++static XimFrameRec xicattr_fr[] =
++{
++    _FRAME(BIT16), 		/* attribute ID */
++    _FRAME(BIT16), 		/* type of the value */
++    _FRAME(BIT16), 		/* length of ic-attribute */
++    _FRAME(BARRAY), 		/* ic-attribute */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++static XimFrameRec ximattribute_fr[] =
++{
++    _FRAME(BIT16), 		/* attribute ID */
++    _FRAME(BIT16), 		/* value length */
++    _FRAME(BARRAY),             /* value */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++static XimFrameRec xicattribute_fr[] =
++{
++    _FRAME(BIT16), 		/* attribute ID */
++    _FRAME(BIT16), 		/* value length */
++    _FRAME(BARRAY),             /* value */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++static XimFrameRec ximtriggerkey_fr[] =
++{
++    _FRAME(BIT32), 		/* keysym */
++    _FRAME(BIT32), 		/* modifier */
++    _FRAME(BIT32), 		/* modifier mask */
++    _FRAME(EOL),
++};
++
++static XimFrameRec encodinginfo_fr[] =
++{
++    _FRAME(BIT16), 		/* length of encoding info */
++    _FRAME(BARRAY), 		/* encoding info */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++static XimFrameRec str_fr[] =
++{
++    _FRAME(BIT8), 		/* number of byte */
++    _FRAME(BARRAY), 		/* string */
++    _FRAME(EOL),
++};
++
++static XimFrameRec xpcs_fr[] =
++{
++    _FRAME(BIT16), 		/* length of string in bytes */
++    _FRAME(BARRAY), 		/* string */
++    _PAD4(2),
++};
++
++static XimFrameRec ext_fr[] =
++{
++    _FRAME(BIT8), 		/* extension major-opcode */
++    _FRAME(BIT8), 		/* extension minor-opcode */
++    _FRAME(BIT16), 		/* length of extension name */
++    _FRAME(BARRAY), 		/* extension name */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++static XimFrameRec inputstyle_fr[] =
++{
++    _FRAME(BIT32), 		/* inputstyle */
++    _FRAME(EOL),
++};
++/* Protocol definitions */
++
++xim_externaldef XimFrameRec attr_head_fr[] =
++{
++    _FRAME(BIT16), 	/* attribute id */
++    _FRAME(BIT16), 	/* attribute length */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec short_fr[] =
++{
++    _FRAME(BIT16), 	/* value */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec long_fr[] =
++{
++    _FRAME(BIT32), 	/* value */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec xrectangle_fr[] =
++{
++    _FRAME(BIT16), 	/* x */
++    _FRAME(BIT16), 	/* y */
++    _FRAME(BIT16), 	/* width */
++    _FRAME(BIT16), 	/* height */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec xpoint_fr[] =
++{
++    _FRAME(BIT16), 	/* x */
++    _FRAME(BIT16), 	/* y */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec fontset_fr[] =
++{
++    _FRAME(BIT16), 	/* length of base font name */
++    _FRAME(BARRAY), 	/* base font name list */
++    _PAD4(2), 		/* unused */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec input_styles_fr[] =
++{
++    _FRAME(BIT16), 		/* number of list */
++    _PAD4(1), 			/* unused */
++    _FRAME(ITER), 		/* XIMStyle list */
++    _FRAME(POINTER),
++    _PTR(inputstyle_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec packet_header_fr[] =
++{
++    _FRAME(BIT8), 		/* major-opcode */
++    _FRAME(BIT8), 		/* minor-opcode */
++    _FRAME(BIT16), 		/* length */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec error_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _FRAME(BIT16), 		/* Error Code */
++    _FRAME(BIT16), 		/* length of error detail */
++    _FRAME(BIT16), 		/* type of error detail */
++    _FRAME(BARRAY), 		/* error detail */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec connect_fr[] =
++{
++    _FRAME(BIT8), 		/* byte order */
++    _PAD2(1), 			/* unused */
++    _FRAME(BIT16), 		/* client-major-protocol-version */
++    _FRAME(BIT16), 		/* client-minor-protocol-version */
++    _BYTE_COUNTER(BIT16, 1), 	/* length of client-auth-protocol-names */
++    _FRAME(ITER), 		/* client-auth-protocol-names */
++    _FRAME(POINTER),
++    _PTR(xpcs_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec connect_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* server-major-protocol-version */
++    _FRAME(BIT16), 		/* server-minor-protocol-version */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec auth_required_fr[] =
++{
++    _FRAME(BIT8), 		/* auth-protocol-index */
++    _FRAME(BIT8), 		/* auth-data1 */
++    _FRAME(BARRAY), 		/* auth-data2 */
++    _PAD4(3),
++    _FRAME(EOL),
++};
++
++
++xim_externaldef XimFrameRec auth_reply_fr[] =
++{
++    _FRAME(BIT8),
++    _FRAME(BARRAY),
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec auth_next_fr[] =
++{
++    _FRAME(BIT8), 		/* auth-data1 */
++    _FRAME(BARRAY), 		/* auth-data2 */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec auth_setup_fr[] =
++{
++    _BYTE_COUNTER(BIT16, 2), 	/* number of client-auth-protocol-names */
++    _PAD4(1), 			/* unused */
++    _FRAME(ITER), 		/* server-auth-protocol-names */
++    _FRAME(POINTER),
++    _PTR(xpcs_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec auth_ng_fr[] =
++{
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec disconnect_fr[] =
++{
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec disconnect_reply_fr[] =
++{
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec open_fr[] =
++{
++    _FRAME(POINTER), 		/* locale name */
++    _PTR(str_fr),
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec open_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of IM attributes supported */
++    _FRAME(ITER), 		/* IM attribute supported */
++    _FRAME(POINTER),
++    _PTR(ximattr_fr),
++    _BYTE_COUNTER(BIT16, 2), 	/* number of IC attribute supported */
++    _PAD4(1), 			/* unused */
++    _FRAME(ITER), 		/* IC attribute supported */
++    _FRAME(POINTER),
++    _PTR(xicattr_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec close_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _PAD4(1), 			/* unused */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec close_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _PAD4(1), 			/* unused */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec register_triggerkeys_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _PAD4(1), 			/* unused */
++    _BYTE_COUNTER(BIT32, 1),    /* byte length of on-keys */
++    _FRAME(ITER), 		/* on-keys list */
++    _FRAME(POINTER),
++    _PTR(ximtriggerkey_fr),
++    _BYTE_COUNTER(BIT32, 1), 	/* byte length of off-keys */
++    _FRAME(ITER), 		/* off-keys list */
++    _FRAME(POINTER),
++    _PTR(ximtriggerkey_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec trigger_notify_fr[] =
++{
++    _FRAME(BIT16), 		/* input-mehotd-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* flag */
++    _FRAME(BIT32), 		/* index of keys list */
++    _FRAME(BIT32), 		/* client-select-event-mask */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec trigger_notify_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec set_event_mask_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* forward-event-mask */
++    _FRAME(BIT32), 		/* synchronous-event-mask */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec encoding_negotiation_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of encodings listed by name */
++    _FRAME(ITER), 		/* supported list of encoding in IM library */
++    _FRAME(POINTER),
++    _PTR(str_fr),
++    _PAD4(1),
++    _BYTE_COUNTER(BIT16, 2), 	/* byte length of encodings listed by
++                                       detailed data */
++    _PAD4(1),
++    _FRAME(ITER), 		/* list of encodings supported in the
++    				   IM library */
++    _FRAME(POINTER),
++    _PTR(encodinginfo_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec encoding_negotiation_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* category of the encoding determined */
++    _FRAME(BIT16), 		/* index of the encoding dterminated */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec query_extension_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of extensions supported
++    				   by the IM library */
++    _FRAME(ITER), 		/* extensions supported by the IM library */
++    _FRAME(POINTER),
++    _PTR(str_fr),
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec query_extension_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of extensions supported
++    				   by the IM server */
++    _FRAME(ITER), 		/* list of extensions supported by the
++    				   IM server */
++    _FRAME(POINTER),
++    _PTR(ext_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec get_im_values_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of im-attribute-id */
++    _FRAME(ITER), 		/* im-attribute-id */
++    _FRAME(BIT16),
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec get_im_values_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of im-attribute returned */
++    _FRAME(ITER), 		/* im-attribute returned */
++    _FRAME(POINTER),
++    _PTR(ximattribute_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec create_ic_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of ic-attributes */
++    _FRAME(ITER), 		/* ic-attributes */
++    _FRAME(POINTER),
++    _PTR(xicattribute_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec create_ic_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec destroy_ic_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec destroy_ic_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec set_ic_values_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _BYTE_COUNTER(BIT16, 2), 	/* byte length of ic-attributes */
++    _PAD4(1),
++    _FRAME(ITER), 		/* ic-attribute */
++    _FRAME(POINTER),
++    _PTR(xicattribute_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec set_ic_values_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec get_ic_values_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of ic-attribute-id */
++    _FRAME(ITER), 		/* ic-attribute */
++    _FRAME(BIT16),
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec get_ic_values_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _BYTE_COUNTER(BIT16, 2), 	/* byte length of ic-attribute */
++    _PAD4(1),
++    _FRAME(ITER), 		/* ic-attribute */
++    _FRAME(POINTER),
++    _PTR(xicattribute_fr),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec set_ic_focus_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec unset_ic_focus_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec forward_event_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _FRAME(BIT16), 		/* sequence number */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec wire_keyevent_fr[] = {
++    _FRAME(BIT8),		/* type */
++    _FRAME(BIT8),		/* detail */
++    _FRAME(BIT16),		/* serial number */
++    _FRAME(BIT32),		/* time */
++    _FRAME(BIT32),		/* root */
++    _FRAME(BIT32),		/* window */
++    _FRAME(BIT32),		/* subwindow */
++    _FRAME(BIT16),		/* rootX */
++    _FRAME(BIT16),		/* rootY */
++    _FRAME(BIT16),		/* X */
++    _FRAME(BIT16),		/* Y */
++    _FRAME(BIT16),		/* state */
++    _FRAME(BIT8),		/* sameScreen */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec sync_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec sync_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++#if 0
++xim_externaldef XimFrameRec commit_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _FRAME(BIT16), 		/* byte length of committed string */
++    _FRAME(BARRAY), 		/* committed string */
++    _PAD4(1),
++    _BYTE_COUNTER(BIT16, 1), 	/* byte length of keysym */
++    _FRAME(ITER), 		/* keysym */
++    _FRAME(BIT32),
++    _PAD4(1),
++    _FRAME(EOL),
++};
++#endif
++
++xim_externaldef XimFrameRec commit_chars_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _FRAME(BIT16), 		/* byte length of committed string */
++    _FRAME(BARRAY), 		/* committed string */
++    _PAD4(1),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec commit_both_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _PAD4(1), 			/* unused */
++    _FRAME(BIT32), 		/* keysym */
++    _FRAME(BIT16), 		/* byte length of committed string */
++    _FRAME(BARRAY), 		/* committed string */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec reset_ic_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec reset_ic_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* byte length of committed string */
++    _FRAME(BARRAY), 		/* committed string */
++    _PAD4(2),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec geometry_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec str_conversion_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* XIMStringConversionPosition */
++    _FRAME(BIT32), 		/* XIMStringConversionType */
++    _FRAME(BIT32), 		/* XIMStringConversionOperation */
++    _FRAME(BIT16), 		/* length to multiply the
++    				   XIMStringConversionType */
++    _FRAME(BIT16), 		/* length of the string to be
++    				   substituted */
++#if 0
++    _FRAME(BARRAY), 		/* string */
++    _PAD4(1),
++#endif
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec str_conversion_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* XIMStringConversionFeedback */
++    _FRAME(BIT16), 		/* length of the retrieved string */
++    _FRAME(BARRAY), 		/* retrieved string */
++    _PAD4(2),
++    _BYTE_COUNTER(BIT16, 2), 	/* number of feedback array */
++    _PAD4(1),
++    _FRAME(ITER), 		/* feedback array */
++    _FRAME(BIT32),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_start_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_start_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* return value */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_draw_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* caret */
++    _FRAME(BIT32), 		/* chg_first */
++    _FRAME(BIT32), 		/* chg_length */
++    _FRAME(BIT32), 		/* status */
++    _FRAME(BIT16), 		/* length of preedit string */
++    _FRAME(BARRAY), 		/* preedit string */
++    _PAD4(2),
++    _BYTE_COUNTER(BIT16, 2), 	/* number of feedback array */
++    _PAD4(1),
++    _FRAME(ITER), 		/* feedback array */
++    _FRAME(BIT32),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_caret_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* position */
++    _FRAME(BIT32), 		/* direction */
++    _FRAME(BIT32), 		/* style */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_caret_reply_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* position */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec preedit_done_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec status_start_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec status_draw_text_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* type */
++    _FRAME(BIT32), 		/* status */
++    _FRAME(BIT16), 		/* length of status string */
++    _FRAME(BARRAY), 		/* status string */
++    _PAD4(2),
++    _BYTE_COUNTER(BIT16, 2), 	/* number of feedback array */
++    _PAD4(1),
++    _FRAME(ITER), 		/* feedback array */
++    _FRAME(BIT32),
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec status_draw_bitmap_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* type */
++    _FRAME(BIT32), 		/* pixmap data */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec status_done_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec ext_set_event_mask_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT32), 		/* filter-event-mask */
++    _FRAME(BIT32), 		/* intercept-event-mask */
++    _FRAME(BIT32), 		/* select-event-mask */
++    _FRAME(BIT32), 		/* forward-event-mask */
++    _FRAME(BIT32), 		/* synchronous-event-mask */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec ext_forward_keyevent_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* flag */
++    _FRAME(BIT16), 		/* sequence number */
++    _FRAME(BIT8), 		/* xEvent.u.u.type */
++    _FRAME(BIT8), 		/* keycode */
++    _FRAME(BIT16), 		/* state */
++    _FRAME(BIT32), 		/* time */
++    _FRAME(BIT32), 		/* window */
++    _FRAME(EOL),
++};
++
++xim_externaldef XimFrameRec ext_move_fr[] =
++{
++    _FRAME(BIT16), 		/* input-method-ID */
++    _FRAME(BIT16), 		/* input-context-ID */
++    _FRAME(BIT16), 		/* X */
++    _FRAME(BIT16), 		/* Y */
++    _FRAME(EOL),
++};
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIc.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIc.c
+new file mode 100644
+index 0000000..47e74c5
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nIc.c
+@@ -0,0 +1,1106 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "FrameMgr.h"
++#include "XimFunc.h"
++
++#define IC_SIZE 64
++
++/* Set IC values */
++static void SetCardAttribute (XICAttribute *value_ret,
++                              char *p,
++                              XICAttr *ic_attr,
++                              int value_length,
++                              int need_swap,
++                              void **value_buf)
++{
++    FrameMgr fm;
++
++    /*endif*/
++    if (value_length == sizeof (CARD8))
++    {
++        memmove (*value_buf, p, value_length);
++    }
++    else if (value_length == sizeof (CARD16))
++    {
++        INT16 value;
++        extern XimFrameRec short_fr[];
++
++        fm = FrameMgrInit (short_fr, (char *) p, need_swap);
++        /* get data */
++        FrameMgrGetToken (fm, value);
++        FrameMgrFree (fm);
++        memmove (*value_buf, &value, value_length);
++    }
++    else if (value_length == sizeof(CARD32))
++    {
++        INT32 value;
++        extern XimFrameRec long_fr[];
++
++        fm = FrameMgrInit (long_fr, (char *) p, need_swap);
++        /* get data */
++        FrameMgrGetToken (fm, value);
++        FrameMgrFree (fm);
++        memmove (*value_buf, &value, value_length);
++    }
++    /*endif*/
++    value_ret->attribute_id = ic_attr->attribute_id;
++    value_ret->name = ic_attr->name;
++    value_ret->name_length = ic_attr->length;
++    value_ret->type = ic_attr->type;
++    value_ret->value_length = value_length;
++    value_ret->value = *value_buf;
++
++    *value_buf += value_length;
++}
++
++static void SetFontAttribute (XICAttribute *value_ret,
++                              char *p,
++                              XICAttr *ic_attr,
++                              int value_length,
++                              int need_swap,
++                              void **value_buf)
++{
++    char *base_name;
++    CARD16 base_length;
++    FrameMgr fm;
++    extern XimFrameRec fontset_fr[];
++
++    fm = FrameMgrInit (fontset_fr, (char *) p, need_swap);
++    /* get data */
++    FrameMgrGetToken (fm, base_length);
++    FrameMgrSetSize (fm, base_length);
++
++    /*endif*/
++    FrameMgrGetToken (fm, base_name);
++    FrameMgrFree(fm);
++    strncpy ((char *) (*value_buf), base_name, base_length);
++    ((char *) *value_buf)[base_length] = (char) 0;
++
++    value_ret->attribute_id = ic_attr->attribute_id;
++    value_ret->name = ic_attr->name;
++    value_ret->name_length = ic_attr->length;
++    value_ret->type = ic_attr->type;
++    value_ret->value_length = value_length;
++    value_ret->value = *value_buf;
++
++    *value_buf += (base_length + 1);
++}
++
++static void SetPointAttribute (XICAttribute *value_ret,
++                               char *p,
++                               XICAttr *ic_attr,
++                               int value_length,
++                               int need_swap,
++                               void **value_buf)
++{
++    XPoint *buf;
++    FrameMgr fm;
++    extern XimFrameRec xpoint_fr[];
++
++    buf = (XPoint *) (*value_buf);
++
++    fm = FrameMgrInit (xpoint_fr, (char *) p, need_swap);
++    /* get data */
++    FrameMgrGetToken (fm, buf->x);
++    FrameMgrGetToken (fm, buf->y);
++    FrameMgrFree (fm);
++
++    value_ret->attribute_id = ic_attr->attribute_id;
++    value_ret->name = ic_attr->name;
++    value_ret->name_length = ic_attr->length;
++    value_ret->type = ic_attr->type;
++    value_ret->value_length = value_length;
++    value_ret->value = (char *) buf;
++
++    *value_buf += value_length;
++}
++
++static void SetRectAttribute (XICAttribute *value_ret,
++                              char *p,
++                              XICAttr *ic_attr,
++                              int value_length,
++                              int need_swap,
++                              void **value_buf)
++{
++    XRectangle *buf;
++    FrameMgr fm;
++    extern XimFrameRec xrectangle_fr[];
++
++    buf = (XRectangle *) (*value_buf);
++
++    fm = FrameMgrInit (xrectangle_fr, (char *) p, need_swap);
++    /* get data */
++    FrameMgrGetToken (fm, buf->x);
++    FrameMgrGetToken (fm, buf->y);
++    FrameMgrGetToken (fm, buf->width);
++    FrameMgrGetToken (fm, buf->height);
++    FrameMgrFree (fm);
++
++    value_ret->attribute_id = ic_attr->attribute_id;
++    value_ret->name = ic_attr->name;
++    value_ret->name_length = ic_attr->length;
++    value_ret->type = ic_attr->type;
++    value_ret->value_length = value_length;
++    value_ret->value = (char *) buf;
++
++    *value_buf += value_length;
++}
++
++#if 0
++static void SetHotKeyAttribute (XICAttribute *value_ret,
++                                char *p,
++                                XICAttr *ic_attr,
++                                int value_length,
++                                int need_swap,
++                                void **value_buf)
++{
++    INT32 list_number;
++    XIMTriggerKey *hotkeys;
++
++    memmove (&list_number, p, sizeof(INT32)); p += sizeof(INT32);
++
++    hotkeys = (XIMTriggerKey *) (*value_buf);
++
++    memmove (hotkeys, p, list_number*sizeof (XIMTriggerKey));
++
++    value_ret->attribute_id = ic_attr->attribute_id;
++    value_ret->name = ic_attr->name;
++    value_ret->name_length = ic_attr->length;
++    value_ret->type = ic_attr->type;
++    value_ret->value_length = value_length;
++    value_ret->value = (char *) hotkeys;
++
++    *value_buf += value_length;
++}
++#endif
++
++/* get IC values */
++static void GetAttrHeader (unsigned char *rec,
++                           XICAttribute *list,
++                           int need_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec attr_head_fr[];
++
++    fm = FrameMgrInit (attr_head_fr, (char *) rec, need_swap);
++    /* put data */
++    FrameMgrPutToken (fm, list->attribute_id);
++    FrameMgrPutToken (fm, list->value_length);
++    FrameMgrFree (fm);
++}
++
++static void GetCardAttribute (char *rec, XICAttribute *list, int need_swap)
++{
++    FrameMgr fm;
++    unsigned char *recp = (unsigned char *) rec;
++
++    GetAttrHeader (recp, list, need_swap);
++    recp += sizeof (CARD16)*2;
++
++    if (list->value_length == sizeof (CARD8))
++    {
++        memmove (recp, list->value, list->value_length);
++    }
++    else if (list->value_length == sizeof (CARD16))
++    {
++        INT16 *value = (INT16 *) list->value;
++        extern XimFrameRec short_fr[];
++
++        fm = FrameMgrInit (short_fr, (char *) recp, need_swap);
++        /* put data */
++        FrameMgrPutToken (fm, *value);
++        FrameMgrFree (fm);
++    }
++    else if (list->value_length == sizeof (CARD32))
++    {
++        INT32 *value = (INT32 *) list->value;
++        extern XimFrameRec long_fr[];
++
++        fm = FrameMgrInit (long_fr, (char *) recp, need_swap);
++        /* put data */
++        FrameMgrPutToken (fm, *value);
++        FrameMgrFree (fm);
++    }
++    /*endif*/
++}
++
++static void GetFontAttribute(char *rec, XICAttribute *list, int need_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec fontset_fr[];
++    char *base_name = (char *) list->value;
++    unsigned char *recp = (unsigned char *) rec;
++
++    GetAttrHeader (recp, list, need_swap);
++    recp += sizeof (CARD16)*2;
++
++    fm = FrameMgrInit (fontset_fr, (char *)recp, need_swap);
++    /* put data */
++    FrameMgrSetSize (fm, list->value_length);
++    FrameMgrPutToken (fm, list->value_length);
++    FrameMgrPutToken (fm, base_name);
++    FrameMgrFree (fm);
++}
++
++static void GetRectAttribute (char *rec, XICAttribute *list, int need_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec xrectangle_fr[];
++    XRectangle *rect = (XRectangle *) list->value;
++    unsigned char *recp = (unsigned char *) rec;
++
++    GetAttrHeader (recp, list, need_swap);
++    recp += sizeof(CARD16)*2;
++
++    fm = FrameMgrInit (xrectangle_fr, (char *) recp, need_swap);
++    /* put data */
++    FrameMgrPutToken (fm, rect->x);
++    FrameMgrPutToken (fm, rect->y);
++    FrameMgrPutToken (fm, rect->width);
++    FrameMgrPutToken (fm, rect->height);
++    FrameMgrFree (fm);
++}
++
++static void GetPointAttribute (char *rec, XICAttribute *list, int need_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec xpoint_fr[];
++    XPoint *rect = (XPoint *) list->value;
++    unsigned char *recp = (unsigned char *) rec;
++
++    GetAttrHeader (recp, list, need_swap);
++    recp += sizeof(CARD16)*2;
++
++    fm = FrameMgrInit (xpoint_fr, (char *) recp, need_swap);
++    /* put data */
++    FrameMgrPutToken (fm, rect->x);
++    FrameMgrPutToken (fm, rect->y);
++    FrameMgrFree (fm);
++}
++
++static int ReadICValue (Xi18n i18n_core,
++                        CARD16 icvalue_id,
++                        int value_length,
++                        void *p,
++                        XICAttribute *value_ret,
++                        CARD16 *number_ret,
++                        int need_swap,
++                        void **value_buf)
++{
++    XICAttr *ic_attr = i18n_core->address.xic_attr;
++    int i;
++
++    *number_ret = (CARD16) 0;
++
++    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++, ic_attr++)
++    {
++        if (ic_attr->attribute_id == icvalue_id)
++            break;
++        /*endif*/
++    }
++    /*endfor*/
++    switch (ic_attr->type)
++    {
++    case XimType_NEST:
++        {
++            int total_length = 0;
++            CARD16 attribute_ID;
++            INT16 attribute_length;
++            unsigned char *p1 = (unsigned char *) p;
++            CARD16 ic_len = 0;
++            CARD16 number;
++            FrameMgr fm;
++            extern XimFrameRec attr_head_fr[];
++
++            while (total_length < value_length)
++            {
++                fm = FrameMgrInit (attr_head_fr, (char *) p1, need_swap);
++                /* get data */
++                FrameMgrGetToken (fm, attribute_ID);
++                FrameMgrGetToken (fm, attribute_length);
++                FrameMgrFree (fm);
++                p1 += sizeof (CARD16)*2;
++                ReadICValue (i18n_core,
++                             attribute_ID,
++                             attribute_length,
++                             p1,
++                             (value_ret + ic_len),
++                             &number,
++                             need_swap,
++                             value_buf);
++                ic_len++;
++                *number_ret += number;
++                p1 += attribute_length;
++                p1 += IMPAD (attribute_length);
++                total_length += (CARD16) sizeof(CARD16)*2
++                                + (INT16) attribute_length
++                                + IMPAD (attribute_length);
++            }
++	    /*endwhile*/
++            return ic_len;
++        }
++
++    case XimType_CARD8:
++    case XimType_CARD16:
++    case XimType_CARD32:
++    case XimType_Window:
++        SetCardAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
++        *number_ret = (CARD16) 1;
++        return *number_ret;
++
++    case XimType_XFontSet:
++        SetFontAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
++        *number_ret = (CARD16) 1;
++        return *number_ret;
++
++    case XimType_XRectangle:
++        SetRectAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
++        *number_ret = (CARD16) 1;
++        return *number_ret;
++
++    case XimType_XPoint:
++        SetPointAttribute(value_ret, p, ic_attr, value_length, need_swap, value_buf);
++        *number_ret = (CARD16) 1;
++        return *number_ret;
++
++#if 0
++    case XimType_XIMHotKeyTriggers:
++        SetHotKeyAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
++	*number_ret = (CARD16) 1;
++	return *number_ret;
++#endif
++    }
++    /*endswitch*/
++    return 0;
++}
++
++static XICAttribute *CreateNestedList (CARD16 attr_id,
++                                       XICAttribute *list,
++                                       int number,
++                                       int need_swap)
++{
++    XICAttribute *nest_list = NULL;
++    register int i;
++    char *values = NULL;
++    char *valuesp;
++    int value_length = 0;
++
++    if (number == 0)
++        return NULL;
++    /*endif*/
++    for (i = 0;  i < number;  i++)
++    {
++        value_length += sizeof (CARD16)*2;
++        value_length += list[i].value_length;
++        value_length += IMPAD (list[i].value_length);
++    }
++    /*endfor*/
++    if ((values = (char *) malloc (value_length)) == NULL)
++        return NULL;
++    /*endif*/
++    memset (values, 0, value_length);
++
++    valuesp = values;
++    for (i = 0;  i < number;  i++)
++    {
++        switch (list[i].type)
++        {
++        case XimType_CARD8:
++        case XimType_CARD16:
++        case XimType_CARD32:
++        case XimType_Window:
++            GetCardAttribute (valuesp, &list[i], need_swap);
++            break;
++
++        case XimType_XFontSet:
++            GetFontAttribute (valuesp, &list[i], need_swap);
++            break;
++
++        case XimType_XRectangle:
++            GetRectAttribute (valuesp, &list[i], need_swap);
++            break;
++
++        case XimType_XPoint:
++            GetPointAttribute (valuesp, &list[i], need_swap);
++            break;
++
++#if 0
++        case XimType_XIMHotKeyTriggers:
++            GetHotKeyAttribute (valuesp, &list[i], need_swap);
++            break;
++#endif
++        }
++        /*endswitch*/
++        valuesp += sizeof (CARD16)*2;
++        valuesp += list[i].value_length;
++        valuesp += IMPAD(list[i].value_length);
++    }
++    /*endfor*/
++
++    nest_list = (XICAttribute *) malloc (sizeof (XICAttribute));
++    if (nest_list == NULL)
++        return NULL;
++    /*endif*/
++    memset (nest_list, 0, sizeof (XICAttribute));
++    nest_list->value = (void *) malloc (value_length);
++    if (nest_list->value == NULL)
++        return NULL;
++    /*endif*/
++    memset (nest_list->value, 0, sizeof (value_length));
++
++    nest_list->attribute_id = attr_id;
++    nest_list->value_length = value_length;
++    memmove (nest_list->value, values, value_length);
++
++    XFree (values);
++    return nest_list;
++}
++
++static Bool IsNestedList (Xi18n i18n_core, CARD16 icvalue_id)
++{
++    XICAttr *ic_attr = i18n_core->address.xic_attr;
++    int i;
++
++    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++, ic_attr++)
++    {
++        if (ic_attr->attribute_id == icvalue_id)
++        {
++            if (ic_attr->type == XimType_NEST)
++                return True;
++            /*endif*/
++            return False;
++        }
++        /*endif*/
++    }
++    /*endfor*/
++    return False;
++}
++
++static Bool IsSeparator (Xi18n i18n_core, CARD16 icvalue_id)
++{
++    return (i18n_core->address.separatorAttr_id == icvalue_id);
++}
++
++static int GetICValue (Xi18n i18n_core,
++                       XICAttribute *attr_ret,
++                       CARD16 *id_list,
++                       int list_num)
++{
++    XICAttr *xic_attr = i18n_core->address.xic_attr;
++    register int i;
++    register int j;
++    register int n;
++
++    i =
++    n = 0;
++    if (IsNestedList (i18n_core, id_list[i]))
++    {
++        i++;
++        while (i < list_num  &&  !IsSeparator (i18n_core, id_list[i]))
++        {
++            for (j = 0;  j < i18n_core->address.ic_attr_num;  j++)
++            {
++                if (xic_attr[j].attribute_id == id_list[i])
++                {
++                    attr_ret[n].attribute_id = xic_attr[j].attribute_id;
++                    attr_ret[n].name_length = xic_attr[j].length;
++                    attr_ret[n].name = malloc (xic_attr[j].length + 1);
++		    strcpy(attr_ret[n].name, xic_attr[j].name);
++                    attr_ret[n].type = xic_attr[j].type;
++                    n++;
++                    i++;
++                    break;
++                }
++                /*endif*/
++            }
++            /*endfor*/
++        }
++        /*endwhile*/
++    }
++    else
++    {
++        for (j = 0;  j < i18n_core->address.ic_attr_num;  j++)
++        {
++            if (xic_attr[j].attribute_id == id_list[i])
++            {
++                attr_ret[n].attribute_id = xic_attr[j].attribute_id;
++                attr_ret[n].name_length = xic_attr[j].length;
++                attr_ret[n].name = malloc (xic_attr[j].length + 1);
++		strcpy(attr_ret[n].name, xic_attr[j].name);
++                attr_ret[n].type = xic_attr[j].type;
++                n++;
++                break;
++            }
++            /*endif*/
++        }
++        /*endfor*/
++    }
++    /*endif*/
++    return n;
++}
++
++static void SwapAttributes (XICAttribute *list,
++			   int number){
++    FrameMgr fm;
++    CARD16 c16;
++    extern XimFrameRec short_fr[];
++    CARD32 c32;
++    extern XimFrameRec long_fr[];
++    XPoint xpoint;
++    extern XimFrameRec xpoint_fr[];
++    XRectangle xrect;
++    extern XimFrameRec xrectangle_fr[];
++    int i;
++
++    for (i = 0; i < number; ++i, ++list) {
++	if (list->value == NULL)
++	    continue;
++	switch (list->type) {
++	case XimType_CARD16:
++	    fm = FrameMgrInit (short_fr, (char *)list->value, 1);
++	    FrameMgrGetToken (fm, c16);
++	    memmove(list->value, &c16, sizeof(CARD16));
++	    FrameMgrFree (fm);
++	    break;
++	case XimType_CARD32:
++	case XimType_Window:
++	    fm = FrameMgrInit (long_fr, (char *)list->value, 1);
++	    FrameMgrGetToken (fm, c32);
++	    memmove(list->value, &c32, sizeof(CARD32));
++	    FrameMgrFree (fm);
++	    break;
++	case XimType_XRectangle:
++	    fm = FrameMgrInit (xrectangle_fr, (char *)list->value, 1);
++	    FrameMgrGetToken (fm, xrect);
++	    memmove(list->value, &xrect, sizeof(XRectangle));
++	    FrameMgrFree (fm);
++	    break;
++	case XimType_XPoint:
++	    fm = FrameMgrInit (xpoint_fr, (char *)list->value, 1);
++	    FrameMgrGetToken (fm, xpoint);
++	    memmove(list->value, &xpoint, sizeof(XPoint));
++	    FrameMgrFree (fm);
++	    break;
++	default:
++	    break;
++	}
++    }
++}
++
++/* called from CreateICMessageProc and SetICValueMessageProc */
++void _Xi18nChangeIC (XIMS ims,
++                     IMProtocol *call_data,
++                     unsigned char *p,
++                     int create_flag)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    FmStatus status;
++    CARD16 byte_length;
++    register int total_size;
++    unsigned char *reply = NULL;
++    register int i;
++    register int attrib_num;
++    XICAttribute *attrib_list;
++    XICAttribute pre_attr[IC_SIZE];
++    XICAttribute sts_attr[IC_SIZE];
++    XICAttribute ic_attr[IC_SIZE];
++    CARD16 preedit_ic_num = 0;
++    CARD16 status_ic_num = 0;
++    CARD16 ic_num = 0;
++    CARD16 connect_id = call_data->any.connect_id;
++    IMChangeICStruct *changeic = (IMChangeICStruct *) &call_data->changeic;
++    extern XimFrameRec create_ic_fr[];
++    extern XimFrameRec create_ic_reply_fr[];
++    extern XimFrameRec set_ic_values_fr[];
++    extern XimFrameRec set_ic_values_reply_fr[];
++    CARD16 input_method_ID;
++
++    void *value_buf = NULL;
++    void *value_buf_ptr;
++
++    register int total_value_length = 0;
++
++    memset (pre_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++    memset (sts_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++    memset (ic_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++
++    if (create_flag == True)
++    {
++        fm = FrameMgrInit (create_ic_fr,
++                           (char *) p,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++        /* get data */
++        FrameMgrGetToken (fm, input_method_ID);
++        FrameMgrGetToken (fm, byte_length);
++    }
++    else
++    {
++        fm = FrameMgrInit (set_ic_values_fr,
++                           (char *) p,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++        /* get data */
++        FrameMgrGetToken (fm, input_method_ID);
++        FrameMgrGetToken (fm, changeic->icid);
++        FrameMgrGetToken (fm, byte_length);
++    }
++    /*endif*/
++    attrib_list = (XICAttribute *) malloc (sizeof (XICAttribute)*IC_SIZE);
++    if (!attrib_list)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (attrib_list, 0, sizeof(XICAttribute)*IC_SIZE);
++
++    attrib_num = 0;
++    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++    {
++        void *value;
++        int value_length;
++
++        FrameMgrGetToken (fm, attrib_list[attrib_num].attribute_id);
++        FrameMgrGetToken (fm, value_length);
++        FrameMgrSetSize (fm, value_length);
++        attrib_list[attrib_num].value_length = value_length;
++        FrameMgrGetToken (fm, value);
++        attrib_list[attrib_num].value = (void *) malloc (value_length + 1);
++        memmove (attrib_list[attrib_num].value, value, value_length);
++	((char *)attrib_list[attrib_num].value)[value_length] = '\0';
++        attrib_num++;
++        total_value_length += (value_length + 1);
++    }
++    /*endwhile*/
++
++    value_buf = (void *) malloc (total_value_length);
++    value_buf_ptr = value_buf;
++
++    if (!value_buf)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        for (i = 0;  i < attrib_num;  i++)
++            XFree (attrib_list[i].value);
++        /*endfor*/
++        XFree (attrib_list);
++        return;
++    }
++    /*endif*/
++
++    for (i = 0;  i < attrib_num;  i++)
++    {
++        CARD16 number;
++
++        if (IsNestedList (i18n_core, attrib_list[i].attribute_id))
++        {
++            if (attrib_list[i].attribute_id
++                == i18n_core->address.preeditAttr_id)
++            {
++                ReadICValue (i18n_core,
++                             attrib_list[i].attribute_id,
++                             attrib_list[i].value_length,
++                             attrib_list[i].value,
++                             &pre_attr[preedit_ic_num],
++                             &number,
++                             _Xi18nNeedSwap(i18n_core, connect_id),
++                             &value_buf_ptr);
++                preedit_ic_num += number;
++            }
++            else if (attrib_list[i].attribute_id == i18n_core->address.statusAttr_id)
++            {
++                ReadICValue (i18n_core,
++                             attrib_list[i].attribute_id,
++                             attrib_list[i].value_length,
++                             attrib_list[i].value,
++                             &sts_attr[status_ic_num],
++                             &number,
++                             _Xi18nNeedSwap (i18n_core, connect_id),
++                             &value_buf_ptr);
++                status_ic_num += number;
++            }
++            else
++            {
++                /* another nested list.. possible? */
++            }
++            /*endif*/
++        }
++        else
++        {
++            ReadICValue (i18n_core,
++                         attrib_list[i].attribute_id,
++                         attrib_list[i].value_length,
++                         attrib_list[i].value,
++                         &ic_attr[ic_num],
++                         &number,
++                         _Xi18nNeedSwap (i18n_core, connect_id),
++                         &value_buf_ptr);
++            ic_num += number;
++        }
++        /*endif*/
++    }
++    /*endfor*/
++    for (i = 0;  i < attrib_num;  i++)
++        XFree (attrib_list[i].value);
++    /*endfor*/
++    XFree (attrib_list);
++
++    FrameMgrFree (fm);
++
++    changeic->preedit_attr_num = preedit_ic_num;
++    changeic->status_attr_num = status_ic_num;
++    changeic->ic_attr_num = ic_num;
++    changeic->preedit_attr = pre_attr;
++    changeic->status_attr = sts_attr;
++    changeic->ic_attr = ic_attr;
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data))) {
++            XFree (value_buf);
++            return;
++        }
++        /*endif*/
++    }
++
++    XFree (value_buf);
++
++    /*endif*/
++    if (create_flag == True)
++    {
++        fm = FrameMgrInit (create_ic_reply_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++    }
++    else
++    {
++        fm = FrameMgrInit (set_ic_values_reply_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, connect_id));
++    }
++    /*endif*/
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, changeic->icid);
++
++    if (create_flag == True)
++    {
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_CREATE_IC_REPLY,
++                           0,
++                           reply,
++                           total_size);
++    }
++    else
++    {
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_SET_IC_VALUES_REPLY,
++                           0,
++                           reply,
++                           total_size);
++    }
++    /*endif*/
++    if (create_flag == True)
++    {
++        int on_key_num = i18n_core->address.on_keys.count_keys;
++        int off_key_num = i18n_core->address.off_keys.count_keys;
++
++        if (on_key_num == 0  &&  off_key_num == 0)
++        {
++            long mask;
++
++            if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
++                mask = i18n_core->address.filterevent_mask;
++            else
++                mask = DEFAULT_FILTER_MASK;
++            /*endif*/
++            /* static event flow is default */
++            _Xi18nSetEventMask (ims,
++                                connect_id,
++                                input_method_ID,
++                                changeic->icid,
++                                mask,
++                                ~mask);
++        }
++        /*endif*/
++    }
++    /*endif*/
++    FrameMgrFree (fm);
++    XFree(reply);
++}
++
++/* called from GetICValueMessageProc */
++void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    FmStatus status;
++    extern XimFrameRec get_ic_values_fr[];
++    extern XimFrameRec get_ic_values_reply_fr[];
++    CARD16 byte_length;
++    register int total_size;
++    unsigned char *reply = NULL;
++    XICAttribute *preedit_ret = NULL;
++    XICAttribute *status_ret = NULL;
++    register int i;
++    register int number;
++    int iter_count;
++    CARD16 *attrID_list;
++    XICAttribute pre_attr[IC_SIZE];
++    XICAttribute sts_attr[IC_SIZE];
++    XICAttribute ic_attr[IC_SIZE];
++    CARD16 pre_count = 0;
++    CARD16 sts_count = 0;
++    CARD16 ic_count = 0;
++    IMChangeICStruct *getic = (IMChangeICStruct *) &call_data->changeic;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    memset (pre_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++    memset (sts_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++    memset (ic_attr, 0, sizeof (XICAttribute)*IC_SIZE);
++
++    fm = FrameMgrInit (get_ic_values_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, getic->icid);
++    FrameMgrGetToken (fm, byte_length);
++
++    attrID_list = (CARD16 *) malloc (sizeof (CARD16)*IC_SIZE);  /* bogus */
++    memset (attrID_list, 0, sizeof (CARD16)*IC_SIZE);
++
++    number = 0;
++    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++        FrameMgrGetToken (fm, attrID_list[number++]);
++    /*endwhile*/
++    FrameMgrFree (fm);
++
++    i = 0;
++    while (i < number)
++    {
++        int read_number;
++
++        if (IsNestedList (i18n_core, attrID_list[i]))
++        {
++            if (attrID_list[i] == i18n_core->address.preeditAttr_id)
++            {
++                read_number = GetICValue (i18n_core,
++                                          &pre_attr[pre_count],
++                                          &attrID_list[i],
++                                          number);
++                i += read_number + 1;
++                pre_count += read_number;
++            }
++            else if (attrID_list[i] == i18n_core->address.statusAttr_id)
++            {
++                read_number = GetICValue (i18n_core,
++                                          &sts_attr[sts_count],
++                                          &attrID_list[i],
++                                          number);
++                i += read_number + 1;
++                sts_count += read_number;
++            }
++            else
++            {
++                /* another nested list.. possible? */
++            }
++            /*endif*/
++        }
++        else
++        {
++            read_number = GetICValue (i18n_core,
++                                      &ic_attr[ic_count],
++                                      &attrID_list[i],
++                                      number);
++            i += read_number;
++            ic_count += read_number;
++        }
++        /*endif*/
++    }
++    /*endwhile*/
++    getic->preedit_attr_num = pre_count;
++    getic->status_attr_num = sts_count;
++    getic->ic_attr_num = ic_count;
++    getic->preedit_attr = pre_attr;
++    getic->status_attr = sts_attr;
++    getic->ic_attr = ic_attr;
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++	if (_Xi18nNeedSwap (i18n_core, connect_id))
++	  SwapAttributes(getic->ic_attr, getic->ic_attr_num);
++    }
++    /*endif*/
++    iter_count = getic->ic_attr_num;
++
++    preedit_ret = CreateNestedList (i18n_core->address.preeditAttr_id,
++                                    getic->preedit_attr,
++                                    getic->preedit_attr_num,
++                                    _Xi18nNeedSwap (i18n_core, connect_id));
++    if (preedit_ret)
++        iter_count++;
++    /*endif*/
++    status_ret = CreateNestedList (i18n_core->address.statusAttr_id,
++                                   getic->status_attr,
++                                   getic->status_attr_num,
++                                   _Xi18nNeedSwap (i18n_core, connect_id));
++    if (status_ret)
++        iter_count++;
++    /*endif*/
++
++    fm = FrameMgrInit (get_ic_values_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set iteration count for list of ic_attribute */
++    FrameMgrSetIterCount (fm, iter_count);
++
++    /* set length of BARRAY item in xicattribute_fr */
++    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
++        FrameMgrSetSize (fm, ic_attr[i].value_length);
++    /*endfor*/
++
++    if (preedit_ret)
++        FrameMgrSetSize (fm, preedit_ret->value_length);
++    /*endif*/
++    if (status_ret)
++        FrameMgrSetSize (fm, status_ret->value_length);
++    /*endif*/
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (reply == NULL)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, getic->icid);
++
++    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
++    {
++        FrameMgrPutToken (fm, ic_attr[i].attribute_id);
++        FrameMgrPutToken (fm, ic_attr[i].value_length);
++        FrameMgrPutToken (fm, ic_attr[i].value);
++    }
++    /*endfor*/
++    if (preedit_ret)
++    {
++        FrameMgrPutToken (fm, preedit_ret->attribute_id);
++        FrameMgrPutToken (fm, preedit_ret->value_length);
++        FrameMgrPutToken (fm, preedit_ret->value);
++    }
++    /*endif*/
++    if (status_ret)
++    {
++        FrameMgrPutToken (fm, status_ret->attribute_id);
++        FrameMgrPutToken (fm, status_ret->value_length);
++        FrameMgrPutToken (fm, status_ret->value);
++    }
++    /*endif*/
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_GET_IC_VALUES_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    XFree (reply);
++    XFree (attrID_list);
++
++    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
++    {
++	if (getic->ic_attr[i].name)
++	    XFree (getic->ic_attr[i].name);
++	/*endif*/
++        if (getic->ic_attr[i].value)
++            XFree (getic->ic_attr[i].value);
++        /*endif*/
++    }
++    /*endfor*/
++    for (i = 0;  i < (int) getic->preedit_attr_num;  i++)
++    {
++	if (getic->preedit_attr[i].name)
++	    XFree (getic->preedit_attr[i].name);
++	/*endif*/
++	if (getic->preedit_attr[i].value)
++	    XFree (getic->preedit_attr[i].value);
++	/*endif*/
++    }
++    /*endfor*/
++    for (i = 0;  i < (int) getic->status_attr_num;  i++)
++    {
++	if (getic->status_attr[i].name)
++	    XFree (getic->status_attr[i].name);
++	/*endif*/
++	if (getic->status_attr[i].value)
++	    XFree (getic->status_attr[i].value);
++	/*endif*/
++    }
++    /*endfor*/
++
++    if (preedit_ret)
++    {
++        XFree (preedit_ret->value);
++        XFree (preedit_ret);
++    }
++    /*endif*/
++    if (status_ret)
++    {
++        XFree (status_ret->value);
++        XFree (status_ret);
++    }
++    /*endif*/
++    FrameMgrFree (fm);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nMethod.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nMethod.c
+new file mode 100644
+index 0000000..c8b43df
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nMethod.c
+@@ -0,0 +1,1150 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include <X11/Xatom.h>
++#ifndef NEED_EVENTS
++#define NEED_EVENTS
++#endif
++#include <X11/Xproto.h>
++#undef NEED_EVENTS
++#include "FrameMgr.h"
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "XimFunc.h"
++
++extern Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
++
++static void *xi18n_setup (Display *, XIMArg *);
++static Status xi18n_openIM (XIMS);
++static Status xi18n_closeIM (XIMS);
++static char *xi18n_setIMValues (XIMS, XIMArg *);
++static char *xi18n_getIMValues (XIMS, XIMArg *);
++static Status xi18n_forwardEvent (XIMS, XPointer);
++static Status xi18n_commit (XIMS, XPointer);
++static int xi18n_callCallback (XIMS, XPointer);
++static int xi18n_preeditStart (XIMS, XPointer);
++static int xi18n_preeditEnd (XIMS, XPointer);
++static int xi18n_syncXlib (XIMS, XPointer);
++
++#ifndef XIM_SERVERS
++#define XIM_SERVERS "XIM_SERVERS"
++#endif
++static Atom XIM_Servers = None;
++
++
++IMMethodsRec Xi18n_im_methods =
++{
++    xi18n_setup,
++    xi18n_openIM,
++    xi18n_closeIM,
++    xi18n_setIMValues,
++    xi18n_getIMValues,
++    xi18n_forwardEvent,
++    xi18n_commit,
++    xi18n_callCallback,
++    xi18n_preeditStart,
++    xi18n_preeditEnd,
++    xi18n_syncXlib,
++};
++
++extern Bool _Xi18nCheckXAddress (Xi18n, TransportSW *, char *);
++extern Bool _Xi18nCheckTransAddress (Xi18n, TransportSW *, char *);
++
++TransportSW _TransR[] =
++{
++    {"X",               1, _Xi18nCheckXAddress},
++#ifdef TCPCONN
++    {"tcp",             3, _Xi18nCheckTransAddress},
++    {"local",           5, _Xi18nCheckTransAddress},
++#endif
++#ifdef DNETCONN
++    {"decnet",          6, _Xi18nCheckTransAddress},
++#endif
++    {(char *) NULL,     0, (Bool (*) ()) NULL}
++};
++
++static Bool GetInputStyles (Xi18n i18n_core, XIMStyles **p_style)
++{
++    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
++    XIMStyles *p;
++    int	i;
++
++    p = &address->input_styles;
++    if ((*p_style = (XIMStyles *) malloc (sizeof (XIMStyles)
++                                          + p->count_styles*sizeof (XIMStyle)))
++        == NULL)
++    {
++        return False;
++    }
++    /*endif*/
++    (*p_style)->count_styles = p->count_styles;
++    (*p_style)->supported_styles = (XIMStyle *) ((XPointer) *p_style + sizeof (XIMStyles));
++    for (i = 0;  i < (int) p->count_styles;  i++)
++        (*p_style)->supported_styles[i] = p->supported_styles[i];
++    /*endfor*/
++    return True;
++}
++
++static Bool GetOnOffKeys (Xi18n i18n_core, long mask, XIMTriggerKeys **p_key)
++{
++    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
++    XIMTriggerKeys *p;
++    int	i;
++
++    if (mask & I18N_ON_KEYS)
++        p = &address->on_keys;
++    else
++        p = &address->off_keys;
++    /*endif*/
++    if ((*p_key = (XIMTriggerKeys *) malloc (sizeof(XIMTriggerKeys)
++                                             + p->count_keys*sizeof(XIMTriggerKey)))
++        == NULL)
++    {
++        return False;
++    }
++    /*endif*/
++    (*p_key)->count_keys = p->count_keys;
++    (*p_key)->keylist =
++        (XIMTriggerKey *) ((XPointer) *p_key + sizeof(XIMTriggerKeys));
++    for (i = 0;  i < (int) p->count_keys;  i++)
++    {
++        (*p_key)->keylist[i].keysym = p->keylist[i].keysym;
++        (*p_key)->keylist[i].modifier = p->keylist[i].modifier;
++        (*p_key)->keylist[i].modifier_mask = p->keylist[i].modifier_mask;
++    }
++    /*endfor*/
++    return True;
++}
++
++static Bool GetEncodings(Xi18n i18n_core, XIMEncodings **p_encoding)
++{
++    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
++    XIMEncodings *p;
++    int	i;
++
++    p = &address->encoding_list;
++
++    if ((*p_encoding = (XIMEncodings *) malloc (sizeof (XIMEncodings)
++                                              + p->count_encodings*sizeof(XIMEncoding))) == NULL)
++    {
++        return False;
++    }
++    /*endif*/
++    (*p_encoding)->count_encodings = p->count_encodings;
++    (*p_encoding)->supported_encodings =
++        (XIMEncoding *) ((XPointer)*p_encoding + sizeof (XIMEncodings));
++    for (i = 0;  i < (int) p->count_encodings;  i++)
++    {
++        (*p_encoding)->supported_encodings[i]
++            = (char *) malloc (strlen (p->supported_encodings[i]) + 1);
++        strcpy ((*p_encoding)->supported_encodings[i],
++                p->supported_encodings[i]);
++    }
++    /*endif*/
++    return True;
++}
++
++static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args)
++{
++    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
++    XIMArg *p;
++
++    if (mode == I18N_OPEN  ||  mode == I18N_SET)
++    {
++        for (p = args;  p->name != NULL;  p++)
++        {
++            if (strcmp (p->name, IMLocale) == 0)
++            {
++                if (address->imvalue_mask & I18N_IM_LOCALE)
++                    return IMLocale;
++                /*endif*/
++                address->im_locale = (char *) malloc (strlen (p->value) + 1);
++                if (!address->im_locale)
++                    return IMLocale;
++                /*endif*/
++                strcpy (address->im_locale, p->value);
++                address->imvalue_mask |= I18N_IM_LOCALE;
++            }
++            else if (strcmp (p->name, IMServerTransport) == 0)
++            {
++                if (address->imvalue_mask & I18N_IM_ADDRESS)
++                    return IMServerTransport;
++                /*endif*/
++                address->im_addr = (char *) malloc (strlen (p->value) + 1);
++                if (!address->im_addr)
++                    return IMServerTransport;
++                /*endif*/
++                strcpy(address->im_addr, p->value);
++                address->imvalue_mask |= I18N_IM_ADDRESS;
++            }
++            else if (strcmp (p->name, IMServerName) == 0)
++            {
++                if (address->imvalue_mask & I18N_IM_NAME)
++                    return IMServerName;
++                /*endif*/
++                address->im_name = (char *) malloc (strlen (p->value) + 1);
++                if (!address->im_name)
++                    return IMServerName;
++                /*endif*/
++                strcpy (address->im_name, p->value);
++                address->imvalue_mask |= I18N_IM_NAME;
++            }
++            else if (strcmp (p->name, IMServerWindow) == 0)
++            {
++                if (address->imvalue_mask & I18N_IMSERVER_WIN)
++                    return IMServerWindow;
++                /*endif*/
++                address->im_window = (Window) p->value;
++                address->imvalue_mask |= I18N_IMSERVER_WIN;
++            }
++            else if (strcmp (p->name, IMInputStyles) == 0)
++            {
++                if (address->imvalue_mask & I18N_INPUT_STYLES)
++                    return IMInputStyles;
++                /*endif*/
++                address->input_styles.count_styles =
++                    ((XIMStyles*)p->value)->count_styles;
++                address->input_styles.supported_styles =
++                    (XIMStyle *) malloc (sizeof (XIMStyle)*address->input_styles.count_styles);
++                if (address->input_styles.supported_styles == (XIMStyle *) NULL)
++                    return IMInputStyles;
++                /*endif*/
++                memmove (address->input_styles.supported_styles,
++                         ((XIMStyles *) p->value)->supported_styles,
++                         sizeof (XIMStyle)*address->input_styles.count_styles);
++                address->imvalue_mask |= I18N_INPUT_STYLES;
++            }
++            else if (strcmp (p->name, IMProtocolHandler) == 0)
++            {
++                address->improto = (IMProtoHandler) p->value;
++                address->imvalue_mask |= I18N_IM_HANDLER;
++            }
++            else if (strcmp (p->name, IMOnKeysList) == 0)
++            {
++                if (address->imvalue_mask & I18N_ON_KEYS)
++                    return IMOnKeysList;
++                /*endif*/
++                address->on_keys.count_keys =
++                    ((XIMTriggerKeys *) p->value)->count_keys;
++                address->on_keys.keylist =
++                    (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->on_keys.count_keys);
++                if (address->on_keys.keylist == (XIMTriggerKey *) NULL)
++                    return IMOnKeysList;
++                /*endif*/
++                memmove (address->on_keys.keylist,
++                         ((XIMTriggerKeys *) p->value)->keylist,
++                         sizeof (XIMTriggerKey)*address->on_keys.count_keys);
++                address->imvalue_mask |= I18N_ON_KEYS;
++            }
++            else if (strcmp (p->name, IMOffKeysList) == 0)
++            {
++                if (address->imvalue_mask & I18N_OFF_KEYS)
++                    return IMOffKeysList;
++                /*endif*/
++                address->off_keys.count_keys =
++                    ((XIMTriggerKeys *) p->value)->count_keys;
++                address->off_keys.keylist =
++                    (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->off_keys.count_keys);
++                if (address->off_keys.keylist == (XIMTriggerKey *) NULL)
++                    return IMOffKeysList;
++                /*endif*/
++                memmove (address->off_keys.keylist,
++                         ((XIMTriggerKeys *) p->value)->keylist,
++                         sizeof (XIMTriggerKey)*address->off_keys.count_keys);
++                address->imvalue_mask |= I18N_OFF_KEYS;
++            }
++            else if (strcmp (p->name, IMEncodingList) == 0)
++            {
++                if (address->imvalue_mask & I18N_ENCODINGS)
++                    return IMEncodingList;
++                /*endif*/
++                address->encoding_list.count_encodings =
++                    ((XIMEncodings *) p->value)->count_encodings;
++                address->encoding_list.supported_encodings =
++                    (XIMEncoding *) malloc (sizeof (XIMEncoding)*address->encoding_list.count_encodings);
++                if (address->encoding_list.supported_encodings
++                    == (XIMEncoding *) NULL)
++                {
++                    return IMEncodingList;
++                }
++                /*endif*/
++                memmove (address->encoding_list.supported_encodings,
++                         ((XIMEncodings *) p->value)->supported_encodings,
++                         sizeof (XIMEncoding)*address->encoding_list.count_encodings);
++                address->imvalue_mask |= I18N_ENCODINGS;
++            }
++            else if (strcmp (p->name, IMFilterEventMask) == 0)
++            {
++                if (address->imvalue_mask & I18N_FILTERMASK)
++                    return IMFilterEventMask;
++                /*endif*/
++                address->filterevent_mask = (long) p->value;
++                address->imvalue_mask |= I18N_FILTERMASK;
++            }
++            /*endif*/
++        }
++        /*endfor*/
++        if (mode == I18N_OPEN)
++        {
++            /* check mandatory IM values */
++            if (!(address->imvalue_mask & I18N_IM_LOCALE))
++            {
++                /* locales must be set in IMOpenIM */
++                return IMLocale;
++            }
++            /*endif*/
++            if (!(address->imvalue_mask & I18N_IM_ADDRESS))
++            {
++                /* address must be set in IMOpenIM */
++                return IMServerTransport;
++            }
++            /*endif*/
++        }
++        /*endif*/
++    }
++    else if (mode == I18N_GET)
++    {
++        for (p = args;  p->name != NULL;  p++)
++        {
++            if (strcmp (p->name, IMLocale) == 0)
++            {
++                p->value = (char *) malloc (strlen (address->im_locale) + 1);
++                if (!p->value)
++                    return IMLocale;
++                /*endif*/
++                strcpy (p->value, address->im_locale);
++            }
++            else if (strcmp (p->name, IMServerTransport) == 0)
++            {
++                p->value = (char *) malloc (strlen (address->im_addr) + 1);
++                if (!p->value)
++                    return IMServerTransport;
++                /*endif*/
++                strcpy (p->value, address->im_addr);
++            }
++            else if (strcmp (p->name, IMServerName) == 0)
++            {
++                if (address->imvalue_mask & I18N_IM_NAME)
++                {
++                    p->value = (char *) malloc (strlen (address->im_name) + 1);
++                    if (!p->value)
++                        return IMServerName;
++                    /*endif*/
++                    strcpy (p->value, address->im_name);
++                }
++                else
++                {
++                    return IMServerName;
++                }
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMServerWindow) == 0)
++            {
++                if (address->imvalue_mask & I18N_IMSERVER_WIN)
++                    *((Window *) (p->value)) = address->im_window;
++                else
++                    return IMServerWindow;
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMInputStyles) == 0)
++            {
++                if (GetInputStyles (i18n_core,
++                                    (XIMStyles **) p->value) == False)
++                {
++                    return IMInputStyles;
++                }
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMProtocolHandler) == 0)
++            {
++                if (address->imvalue_mask & I18N_IM_HANDLER)
++                    *((IMProtoHandler *) (p->value)) = address->improto;
++                else
++                    return IMProtocolHandler;
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMOnKeysList) == 0)
++            {
++                if (address->imvalue_mask & I18N_ON_KEYS)
++                {
++                    if (GetOnOffKeys (i18n_core,
++                                      I18N_ON_KEYS,
++                                      (XIMTriggerKeys **) p->value) == False)
++                    {
++                        return IMOnKeysList;
++                    }
++                    /*endif*/
++                }
++                else
++                {
++                    return IMOnKeysList;
++                }
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMOffKeysList) == 0)
++            {
++                if (address->imvalue_mask & I18N_OFF_KEYS)
++                {
++                    if (GetOnOffKeys (i18n_core,
++                                      I18N_OFF_KEYS,
++                                      (XIMTriggerKeys **) p->value) == False)
++                    {
++                        return IMOffKeysList;
++                    }
++                    /*endif*/
++                }
++                else
++                {
++                    return IMOffKeysList;
++                }
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMEncodingList) == 0)
++            {
++                if (address->imvalue_mask & I18N_ENCODINGS)
++                {
++                    if (GetEncodings (i18n_core,
++                                      (XIMEncodings **) p->value) == False)
++                    {
++                        return IMEncodingList;
++                    }
++                    /*endif*/
++                }
++                else
++                {
++                    return IMEncodingList;
++                }
++                /*endif*/
++            }
++            else if (strcmp (p->name, IMFilterEventMask) == 0)
++            {
++                if (address->imvalue_mask & I18N_FILTERMASK)
++                    *((long *) (p->value)) = address->filterevent_mask;
++                else
++                    return IMFilterEventMask;
++                /*endif*/
++            }
++            /*endif*/
++        }
++        /*endfor*/
++    }
++    /*endif*/
++    return NULL;
++}
++
++static int CheckIMName (Xi18n i18n_core)
++{
++    char *address = i18n_core->address.im_addr;
++    int i;
++
++    for (i = 0;  _TransR[i].transportname;  i++)
++    {
++        while (*address == ' '  ||  *address == '\t')
++            address++;
++        /*endwhile*/
++        if (strncmp (address,
++                     _TransR[i].transportname,
++                     _TransR[i].namelen) == 0
++            &&
++            address[_TransR[i].namelen] == '/')
++        {
++            if (_TransR[i].checkAddr (i18n_core,
++                                      &_TransR[i],
++                                      address + _TransR[i].namelen + 1) == True)
++            {
++                return True;
++            }
++            /*endif*/
++            return False;
++        }
++        /*endif*/
++    }
++    /*endfor*/
++    return False;
++}
++
++static int SetXi18nSelectionOwner(Xi18n i18n_core)
++{
++    Display *dpy = i18n_core->address.dpy;
++    Window ims_win = i18n_core->address.im_window;
++    Window root = RootWindow (dpy, DefaultScreen (dpy));
++    Atom realtype;
++    int realformat;
++    unsigned long bytesafter;
++    long *data=NULL;
++    unsigned long length;
++    Atom atom;
++    int i;
++    int found;
++    int forse = False;
++    char buf[256];
++
++    (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
++    if ((atom = XInternAtom(dpy, buf, False)) == 0)
++        return False;
++    i18n_core->address.selection = atom;
++
++    if (XIM_Servers == None)
++        XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
++    /*endif*/
++    XGetWindowProperty (dpy,
++                        root,
++                        XIM_Servers,
++                        0L,
++                        1000000L,
++                        False,
++                        XA_ATOM,
++                        &realtype,
++                        &realformat,
++                        &length,
++                        &bytesafter,
++                        (unsigned char **) (&data));
++    if (realtype != None && (realtype != XA_ATOM || realformat != 32)) {
++        if (data != NULL)
++            XFree ((char *) data);
++        return False;
++    }
++
++    found = False;
++    for (i = 0; i < length; i++) {
++        if (data[i] == atom) {
++            Window owner;
++            found = True;
++            if ((owner = XGetSelectionOwner (dpy, atom)) != ims_win) {
++                if (owner == None  ||  forse == True)
++                    XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
++                else
++                    return False;
++            }
++            break;
++        }
++    }
++
++    if (found == False) {
++        XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
++        XChangeProperty (dpy,
++                         root,
++                         XIM_Servers,
++                         XA_ATOM,
++                         32,
++                         PropModePrepend,
++                         (unsigned char *) &atom,
++                         1);
++    }
++    else {
++	/*
++	 * We always need to generate the PropertyNotify to the Root Window
++	 */
++        XChangeProperty (dpy,
++                         root,
++                         XIM_Servers,
++                         XA_ATOM,
++                         32,
++                         PropModePrepend,
++                         (unsigned char *) data,
++                         0);
++    }
++    if (data != NULL)
++        XFree ((char *) data);
++
++    /* Intern "LOCALES" and "TRANSOPORT" Target Atoms */
++    i18n_core->address.Localename = XInternAtom (dpy, LOCALES, False);
++    i18n_core->address.Transportname = XInternAtom (dpy, TRANSPORT, False);
++    return (XGetSelectionOwner (dpy, atom) == ims_win);
++}
++
++static int DeleteXi18nAtom(Xi18n i18n_core)
++{
++    Display *dpy = i18n_core->address.dpy;
++    Window root = RootWindow (dpy, DefaultScreen (dpy));
++    Atom realtype;
++    int realformat;
++    unsigned long bytesafter;
++    long *data=NULL;
++    unsigned long length;
++    Atom atom;
++    int i, ret;
++    int found;
++    char buf[256];
++
++    (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
++    if ((atom = XInternAtom(dpy, buf, False)) == 0)
++        return False;
++    i18n_core->address.selection = atom;
++
++    if (XIM_Servers == None)
++        XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
++    XGetWindowProperty (dpy,
++                        root,
++                        XIM_Servers,
++                        0L,
++                        1000000L,
++                        False,
++                        XA_ATOM,
++                        &realtype,
++                        &realformat,
++                        &length,
++                        &bytesafter,
++                        (unsigned char **) (&data));
++    if (realtype != XA_ATOM || realformat != 32) {
++        if (data != NULL)
++            XFree ((char *) data);
++        return False;
++    }
++
++    found = False;
++    for (i = 0; i < length; i++) {
++        if (data[i] == atom) {
++            found = True;
++            break;
++        }
++    }
++
++    if (found == True) {
++        for (i=i+1; i<length; i++)
++            data[i-1] = data[i];
++        XChangeProperty (dpy,
++                         root,
++                         XIM_Servers,
++                         XA_ATOM,
++                         32,
++                         PropModeReplace,
++                         (unsigned char *)data,
++                         length-1);
++        ret = True;
++    }
++    else {
++        XChangeProperty (dpy,
++                         root,
++                         XIM_Servers,
++                         XA_ATOM,
++                         32,
++                         PropModePrepend,
++                         (unsigned char *)data,
++                         0);
++        ret = False;
++    }
++    if (data != NULL)
++        XFree ((char *) data);
++    return ret;
++}
++
++
++/* XIM protocol methods */
++static void *xi18n_setup (Display *dpy, XIMArg *args)
++{
++    Xi18n i18n_core;
++    CARD16 endian = 1;
++
++    if ((i18n_core = (Xi18n) malloc (sizeof (Xi18nCore))) == (Xi18n) NULL)
++        return NULL;
++    /*endif*/
++
++    memset (i18n_core, 0, sizeof (Xi18nCore));
++
++    i18n_core->address.dpy = dpy;
++
++    if (ParseArgs (i18n_core, I18N_OPEN, args) != NULL)
++    {
++        XFree (i18n_core);
++        return NULL;
++    }
++    /*endif*/
++    if (*(char *) &endian)
++        i18n_core->address.im_byteOrder = 'l';
++    else
++        i18n_core->address.im_byteOrder = 'B';
++    /*endif*/
++
++    /* install IMAttr and ICAttr list in i18n_core */
++    _Xi18nInitAttrList (i18n_core);
++
++    /* install IMExtension list in i18n_core */
++    _Xi18nInitExtension (i18n_core);
++
++    return i18n_core;
++}
++
++static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev)
++{
++    XEvent event;
++    Display *dpy = i18n_core->address.dpy;
++    char buf[4096];
++
++    event.type = SelectionNotify;
++    event.xselection.requestor = ev->requestor;
++    event.xselection.selection = ev->selection;
++    event.xselection.target = ev->target;
++    event.xselection.time = ev->time;
++    event.xselection.property = ev->property;
++    if (ev->target == i18n_core->address.Localename)
++    {
++        snprintf (buf, 4096, "@locale=%s", i18n_core->address.im_locale);
++    }
++    else if (ev->target == i18n_core->address.Transportname)
++    {
++        snprintf (buf, 4096, "@transport=%s", i18n_core->address.im_addr);
++    }
++    /*endif*/
++    XChangeProperty (dpy,
++                     event.xselection.requestor,
++                     ev->target,
++                     ev->target,
++                     8,
++                     PropModeReplace,
++                     (unsigned char *) buf,
++                     strlen (buf));
++    XSendEvent (dpy, event.xselection.requestor, False, NoEventMask, &event);
++    XFlush (i18n_core->address.dpy);
++}
++
++static Bool WaitXSelectionRequest (Display *dpy,
++                                   Window win,
++                                   XEvent *ev,
++                                   XPointer client_data)
++{
++    XIMS ims = (XIMS) client_data;
++    Xi18n i18n_core = ims->protocol;
++
++    if (((XSelectionRequestEvent *) ev)->selection
++        == i18n_core->address.selection)
++    {
++        ReturnSelectionNotify (i18n_core, (XSelectionRequestEvent *) ev);
++        return True;
++    }
++    /*endif*/
++    return False;
++}
++
++static Status xi18n_openIM(XIMS ims)
++{
++    Xi18n i18n_core = ims->protocol;
++    Display *dpy = i18n_core->address.dpy;
++
++    if (!CheckIMName (i18n_core)
++        ||
++        !SetXi18nSelectionOwner (i18n_core)
++        ||
++        !i18n_core->methods.begin (ims))
++    {
++        XFree (i18n_core->address.im_name);
++        XFree (i18n_core->address.im_locale);
++        XFree (i18n_core->address.im_addr);
++        XFree (i18n_core);
++        return False;
++    }
++    /*endif*/
++
++    _XRegisterFilterByType (dpy,
++                            i18n_core->address.im_window,
++                            SelectionRequest,
++                            SelectionRequest,
++                            WaitXSelectionRequest,
++                            (XPointer)ims);
++    XFlush(dpy);
++    return True;
++}
++
++static Status xi18n_closeIM(XIMS ims)
++{
++    Xi18n i18n_core = ims->protocol;
++    Display *dpy = i18n_core->address.dpy;
++
++    DeleteXi18nAtom(i18n_core);
++    if (!i18n_core->methods.end (ims))
++        return False;
++
++    _XUnregisterFilter (dpy,
++                        i18n_core->address.im_window,
++                        WaitXSelectionRequest,
++                        (XPointer)ims);
++    XFree (i18n_core->address.im_name);
++    XFree (i18n_core->address.im_locale);
++    XFree (i18n_core->address.im_addr);
++    XFree (i18n_core);
++    return True;
++}
++
++static char *xi18n_setIMValues (XIMS ims, XIMArg *args)
++{
++    Xi18n i18n_core = ims->protocol;
++    char *ret;
++
++    if ((ret = ParseArgs (i18n_core, I18N_SET, args)) != NULL)
++        return ret;
++    /*endif*/
++    return NULL;
++}
++
++static char *xi18n_getIMValues (XIMS ims, XIMArg *args)
++{
++    Xi18n i18n_core = ims->protocol;
++    char *ret;
++
++    if ((ret = ParseArgs (i18n_core, I18N_GET, args)) != NULL)
++        return ret;
++    /*endif*/
++    return NULL;
++}
++
++static void EventToWireEvent (XEvent *ev, xEvent *event,
++			      CARD16 *serial, Bool byte_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec wire_keyevent_fr[];
++    extern XimFrameRec short_fr[];
++    BYTE b;
++    CARD16 c16;
++    CARD32 c32;
++
++    *serial = (CARD16)(ev->xany.serial >> 16);
++    switch (ev->type) {
++      case KeyPress:
++      case KeyRelease:
++	{
++	    XKeyEvent *kev = (XKeyEvent*)ev;
++	    /* create FrameMgr */
++	    fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
++
++	    /* set values */
++	    b = (BYTE)kev->type;          FrameMgrPutToken(fm, b);
++	    b = (BYTE)kev->keycode;       FrameMgrPutToken(fm, b);
++	    c16 = (CARD16)(kev->serial & (unsigned long)0xffff);
++					  FrameMgrPutToken(fm, c16);
++	    c32 = (CARD32)kev->time;      FrameMgrPutToken(fm, c32);
++	    c32 = (CARD32)kev->root;      FrameMgrPutToken(fm, c32);
++	    c32 = (CARD32)kev->window;    FrameMgrPutToken(fm, c32);
++	    c32 = (CARD32)kev->subwindow; FrameMgrPutToken(fm, c32);
++	    c16 = (CARD16)kev->x_root;    FrameMgrPutToken(fm, c16);
++	    c16 = (CARD16)kev->y_root;    FrameMgrPutToken(fm, c16);
++	    c16 = (CARD16)kev->x;         FrameMgrPutToken(fm, c16);
++	    c16 = (CARD16)kev->y;         FrameMgrPutToken(fm, c16);
++	    c16 = (CARD16)kev->state;     FrameMgrPutToken(fm, c16);
++	    b = (BYTE)kev->same_screen;   FrameMgrPutToken(fm, b);
++	}
++	break;
++      default:
++	  /* create FrameMgr */
++	  fm = FrameMgrInit(short_fr, (char *)(&(event->u.u.sequenceNumber)),
++			    byte_swap);
++	  c16 = (CARD16)(ev->xany.serial & (unsigned long)0xffff);
++	  FrameMgrPutToken(fm, c16);
++	  break;
++    }
++    /* free FrameMgr */
++    FrameMgrFree(fm);
++}
++
++static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
++{
++    Xi18n i18n_core = ims->protocol;
++    IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
++    FrameMgr fm;
++    extern XimFrameRec forward_event_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    unsigned char *replyp;
++    CARD16 serial;
++    int event_size;
++    Xi18nClient *client;
++
++    client = (Xi18nClient *) _Xi18nFindClient (i18n_core, call_data->connect_id);
++
++    /* create FrameMgr */
++    fm = FrameMgrInit (forward_event_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, call_data->connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    event_size = sizeof (xEvent);
++    reply = (unsigned char *) malloc (total_size + event_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims,
++                           call_data->connect_id,
++                           XIM_ERROR,
++                           0,
++                           0,
++                           0);
++        return False;
++    }
++    /*endif*/
++    memset (reply, 0, total_size + event_size);
++    FrameMgrSetBuffer (fm, reply);
++    replyp = reply;
++
++    call_data->sync_bit = 1; 	/* always sync */
++    client->sync = True;
++
++    FrameMgrPutToken (fm, call_data->connect_id);
++    FrameMgrPutToken (fm, call_data->icid);
++    FrameMgrPutToken (fm, call_data->sync_bit);
++
++    replyp += total_size;
++    EventToWireEvent (&(call_data->event),
++                      (xEvent *) replyp,
++                      &serial,
++                      _Xi18nNeedSwap (i18n_core, call_data->connect_id));
++
++    FrameMgrPutToken (fm, serial);
++
++    _Xi18nSendMessage (ims,
++                       call_data->connect_id,
++                       XIM_FORWARD_EVENT,
++                       0,
++                       reply,
++                       total_size + event_size);
++
++    XFree (reply);
++    FrameMgrFree (fm);
++
++    return True;
++}
++
++static Status xi18n_commit (XIMS ims, XPointer xp)
++{
++    Xi18n i18n_core = ims->protocol;
++    IMCommitStruct *call_data = (IMCommitStruct *)xp;
++    FrameMgr fm;
++    extern XimFrameRec commit_chars_fr[];
++    extern XimFrameRec commit_both_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    CARD16 str_length;
++
++    call_data->flag |= XimSYNCHRONUS;  /* always sync */
++
++    if (!(call_data->flag & XimLookupKeySym)
++        &&
++        (call_data->flag & XimLookupChars))
++    {
++        fm = FrameMgrInit (commit_chars_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, call_data->connect_id));
++
++        /* set length of STRING8 */
++        str_length = strlen (call_data->commit_string);
++        FrameMgrSetSize (fm, str_length);
++        total_size = FrameMgrGetTotalSize (fm);
++        reply = (unsigned char *) malloc (total_size);
++        if (!reply)
++        {
++            _Xi18nSendMessage (ims,
++                               call_data->connect_id,
++                               XIM_ERROR,
++                               0,
++                               0,
++                               0);
++            return False;
++        }
++        /*endif*/
++        memset (reply, 0, total_size);
++        FrameMgrSetBuffer (fm, reply);
++
++        str_length = FrameMgrGetSize (fm);
++        FrameMgrPutToken (fm, call_data->connect_id);
++        FrameMgrPutToken (fm, call_data->icid);
++        FrameMgrPutToken (fm, call_data->flag);
++        FrameMgrPutToken (fm, str_length);
++        FrameMgrPutToken (fm, call_data->commit_string);
++    }
++    else
++    {
++        fm = FrameMgrInit (commit_both_fr,
++                           NULL,
++                           _Xi18nNeedSwap (i18n_core, call_data->connect_id));
++        /* set length of STRING8 */
++        str_length = strlen (call_data->commit_string);
++        if (str_length > 0)
++            FrameMgrSetSize (fm, str_length);
++        /*endif*/
++        total_size = FrameMgrGetTotalSize (fm);
++        reply = (unsigned char *) malloc (total_size);
++        if (!reply)
++        {
++            _Xi18nSendMessage (ims,
++                               call_data->connect_id,
++                               XIM_ERROR,
++                               0,
++                               0,
++                               0);
++            return False;
++        }
++        /*endif*/
++        FrameMgrSetBuffer (fm, reply);
++        FrameMgrPutToken (fm, call_data->connect_id);
++        FrameMgrPutToken (fm, call_data->icid);
++        FrameMgrPutToken (fm, call_data->flag);
++        FrameMgrPutToken (fm, call_data->keysym);
++        if (str_length > 0)
++        {
++            str_length = FrameMgrGetSize (fm);
++            FrameMgrPutToken (fm, str_length);
++            FrameMgrPutToken (fm, call_data->commit_string);
++        }
++        /*endif*/
++    }
++    /*endif*/
++    _Xi18nSendMessage (ims,
++                       call_data->connect_id,
++                       XIM_COMMIT,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    return True;
++}
++
++static int xi18n_callCallback (XIMS ims, XPointer xp)
++{
++    IMProtocol *call_data = (IMProtocol *)xp;
++    switch (call_data->major_code)
++    {
++    case XIM_GEOMETRY:
++        return _Xi18nGeometryCallback (ims, call_data);
++
++    case XIM_PREEDIT_START:
++        return _Xi18nPreeditStartCallback (ims, call_data);
++
++    case XIM_PREEDIT_DRAW:
++        return _Xi18nPreeditDrawCallback (ims, call_data);
++
++    case XIM_PREEDIT_CARET:
++        return _Xi18nPreeditCaretCallback (ims, call_data);
++
++    case XIM_PREEDIT_DONE:
++        return _Xi18nPreeditDoneCallback (ims, call_data);
++
++    case XIM_STATUS_START:
++        return _Xi18nStatusStartCallback (ims, call_data);
++
++    case XIM_STATUS_DRAW:
++        return _Xi18nStatusDrawCallback (ims, call_data);
++
++    case XIM_STATUS_DONE:
++        return _Xi18nStatusDoneCallback (ims, call_data);
++
++    case XIM_STR_CONVERSION:
++        return _Xi18nStringConversionCallback (ims, call_data);
++    }
++    /*endswitch*/
++    return False;
++}
++
++/* preeditStart and preeditEnd are used only for Dynamic Event Flow. */
++static int xi18n_preeditStart (XIMS ims, XPointer xp)
++{
++    IMProtocol *call_data = (IMProtocol *)xp;
++    Xi18n i18n_core = ims->protocol;
++    IMPreeditStateStruct *preedit_state =
++        (IMPreeditStateStruct *) &call_data->preedit_state;
++    long mask;
++    int on_key_num = i18n_core->address.on_keys.count_keys;
++    int off_key_num = i18n_core->address.off_keys.count_keys;
++
++    if (on_key_num == 0  &&  off_key_num == 0)
++        return False;
++    /*endif*/
++    if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
++        mask = i18n_core->address.filterevent_mask;
++    else
++        mask = DEFAULT_FILTER_MASK;
++    /*endif*/
++    _Xi18nSetEventMask (ims,
++                        preedit_state->connect_id,
++                        preedit_state->connect_id,
++                        preedit_state->icid,
++                        mask,
++                        ~mask);
++    return True;
++}
++
++static int xi18n_preeditEnd (XIMS ims, XPointer xp)
++{
++    IMProtocol *call_data = (IMProtocol *)xp;
++    Xi18n i18n_core = ims->protocol;
++    int on_key_num = i18n_core->address.on_keys.count_keys;
++    int off_key_num = i18n_core->address.off_keys.count_keys;
++    IMPreeditStateStruct *preedit_state;
++
++    preedit_state = (IMPreeditStateStruct *) &call_data->preedit_state;
++
++    if (on_key_num == 0  &&  off_key_num == 0)
++        return False;
++    /*endif*/
++
++    _Xi18nSetEventMask (ims,
++                        preedit_state->connect_id,
++                        preedit_state->connect_id,
++                        preedit_state->icid,
++                        0,
++                        0);
++    return True;
++}
++
++static int xi18n_syncXlib (XIMS ims, XPointer xp)
++{
++    IMProtocol *call_data = (IMProtocol *)xp;
++    Xi18n i18n_core = ims->protocol;
++    IMSyncXlibStruct *sync_xlib;
++
++    extern XimFrameRec sync_fr[];
++    FrameMgr fm;
++    CARD16 connect_id = call_data->any.connect_id;
++    int total_size;
++    unsigned char *reply;
++
++    sync_xlib = (IMSyncXlibStruct *) &call_data->sync_xlib;
++    fm = FrameMgrInit (sync_fr, NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    total_size = FrameMgrGetTotalSize(fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply) {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return False;
++    }
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    /* input input-method ID */
++    FrameMgrPutToken (fm, connect_id);
++    /* input input-context ID */
++    FrameMgrPutToken (fm, sync_xlib->icid);
++    _Xi18nSendMessage (ims, connect_id, XIM_SYNC, 0, reply, total_size);
++
++    FrameMgrFree (fm);
++    XFree(reply);
++    return True;
++}
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nPtHdr.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nPtHdr.c
+new file mode 100644
+index 0000000..17e41b7
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nPtHdr.c
+@@ -0,0 +1,1906 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <stdlib.h>
++#include <sys/param.h>
++#include <X11/Xlib.h>
++#ifndef NEED_EVENTS
++#define NEED_EVENTS
++#endif
++#include <X11/Xproto.h>
++#undef NEED_EVENTS
++#include "FrameMgr.h"
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "XimFunc.h"
++
++#ifdef XIM_DEBUG
++#include <stdio.h>
++
++static void	DebugLog(char * msg)
++{
++	fprintf(stderr, msg);
++}
++#endif
++
++extern Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
++
++static void DiscardQueue (XIMS ims, CARD16 connect_id)
++{
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient *client = (Xi18nClient *) _Xi18nFindClient (i18n_core,
++                                                            connect_id);
++
++    if (client != NULL) {
++	client->sync = False;
++	while (client->pending != NULL) {
++	    XIMPending* pending = client->pending;
++
++	    client->pending = pending->next;
++
++	    XFree(pending->p);
++	    XFree(pending);
++	}
++    }
++}
++
++static void DiscardAllQueue(XIMS ims)
++{
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient* client = i18n_core->address.clients;
++
++    while (client != NULL) {
++	if (client->sync) {
++	    DiscardQueue(ims, client->connect_id);
++	}
++	client = client->next;
++    }
++}
++
++static void GetProtocolVersion (CARD16 client_major,
++                                CARD16 client_minor,
++                                CARD16 *server_major,
++                                CARD16 *server_minor)
++{
++    *server_major = client_major;
++    *server_minor = client_minor;
++}
++
++static void ConnectMessageProc (XIMS ims,
++                                IMProtocol *call_data,
++                                unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec connect_fr[], connect_reply_fr[];
++    register int total_size;
++    CARD16 server_major_version, server_minor_version;
++    unsigned char *reply = NULL;
++    IMConnectStruct *imconnect =
++        (IMConnectStruct*) &call_data->imconnect;
++    CARD16 connect_id = call_data->any.connect_id;
++
++    fm = FrameMgrInit (connect_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, imconnect->byte_order);
++    FrameMgrGetToken (fm, imconnect->major_version);
++    FrameMgrGetToken (fm, imconnect->minor_version);
++
++    FrameMgrFree (fm);
++
++    GetProtocolVersion (imconnect->major_version,
++                        imconnect->minor_version,
++                        &server_major_version,
++                        &server_minor_version);
++#ifdef PROTOCOL_RICH
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++#endif  /* PROTOCOL_RICH */
++
++    fm = FrameMgrInit (connect_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, server_major_version);
++    FrameMgrPutToken (fm, server_minor_version);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_CONNECT_REPLY,
++                       0,
++                       reply,
++                       total_size);
++
++    FrameMgrFree (fm);
++    XFree (reply);
++}
++
++static void DisConnectMessageProc (XIMS ims, IMProtocol *call_data)
++{
++    Xi18n i18n_core = ims->protocol;
++    unsigned char *reply = NULL;
++    CARD16 connect_id = call_data->any.connect_id;
++
++#ifdef PROTOCOL_RICH
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++#endif  /* PROTOCOL_RICH */
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_DISCONNECT_REPLY,
++                       0,
++                       reply,
++                       0);
++
++    i18n_core->methods.disconnect (ims, connect_id);
++}
++
++static void OpenMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec open_fr[];
++    extern XimFrameRec open_reply_fr[];
++    unsigned char *reply = NULL;
++    int str_size;
++    register int i, total_size;
++    CARD16 connect_id = call_data->any.connect_id;
++    int str_length;
++    char *name;
++    IMOpenStruct *imopen = (IMOpenStruct *) &call_data->imopen;
++
++    fm = FrameMgrInit (open_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, str_length);
++    FrameMgrSetSize (fm, str_length);
++    FrameMgrGetToken (fm, name);
++    imopen->lang.length = str_length;
++    imopen->lang.name = malloc (str_length + 1);
++    strncpy (imopen->lang.name, name, str_length);
++    imopen->lang.name[str_length] = (char) 0;
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++    if ((i18n_core->address.imvalue_mask & I18N_ON_KEYS)
++        ||
++        (i18n_core->address.imvalue_mask & I18N_OFF_KEYS))
++    {
++        _Xi18nSendTriggerKey (ims, connect_id);
++    }
++    /*endif*/
++    XFree (imopen->lang.name);
++
++    fm = FrameMgrInit (open_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set iteration count for list of imattr */
++    FrameMgrSetIterCount (fm, i18n_core->address.im_attr_num);
++
++    /* set length of BARRAY item in ximattr_fr */
++    for (i = 0;  i < i18n_core->address.im_attr_num;  i++)
++    {
++        str_size = strlen (i18n_core->address.xim_attr[i].name);
++        FrameMgrSetSize (fm, str_size);
++    }
++    /*endfor*/
++    /* set iteration count for list of icattr */
++    FrameMgrSetIterCount (fm, i18n_core->address.ic_attr_num);
++    /* set length of BARRAY item in xicattr_fr */
++    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++)
++    {
++        str_size = strlen (i18n_core->address.xic_attr[i].name);
++        FrameMgrSetSize (fm, str_size);
++    }
++    /*endfor*/
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    /* input input-method ID */
++    FrameMgrPutToken (fm, connect_id);
++
++    for (i = 0;  i < i18n_core->address.im_attr_num;  i++)
++    {
++        str_size = FrameMgrGetSize (fm);
++        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].attribute_id);
++        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].type);
++        FrameMgrPutToken (fm, str_size);
++        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].name);
++    }
++    /*endfor*/
++    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++)
++    {
++        str_size = FrameMgrGetSize (fm);
++        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].attribute_id);
++        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].type);
++        FrameMgrPutToken (fm, str_size);
++        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].name);
++    }
++    /*endfor*/
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_OPEN_REPLY,
++                       0,
++                       reply,
++                       total_size);
++
++    FrameMgrFree (fm);
++    XFree (reply);
++}
++
++static void CloseMessageProc (XIMS ims,
++                              IMProtocol *call_data,
++                              unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec close_fr[];
++    extern XimFrameRec close_reply_fr[];
++    unsigned char *reply = NULL;
++    register int total_size;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (close_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    FrameMgrGetToken (fm, input_method_ID);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++
++    fm = FrameMgrInit (close_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_ERROR,
++                           0,
++                           0,
++                           0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_CLOSE_REPLY,
++                       0,
++                       reply,
++                       total_size);
++
++    FrameMgrFree (fm);
++    XFree (reply);
++}
++
++static XIMExt *MakeExtensionList (Xi18n i18n_core,
++                                  XIMStr *lib_extension,
++                                  int number,
++                                  int *reply_number)
++{
++    XIMExt *ext_list;
++    XIMExt *im_ext = (XIMExt *) i18n_core->address.extension;
++    int im_ext_len = i18n_core->address.ext_num;
++    int i;
++    int j;
++
++    *reply_number = 0;
++
++    if (number == 0)
++    {
++        /* query all extensions */
++        *reply_number = im_ext_len;
++    }
++    else
++    {
++        for (i = 0;  i < im_ext_len;  i++)
++        {
++            for (j = 0;  j < (int) number;  j++)
++            {
++                if (strcmp (lib_extension[j].name, im_ext[i].name) == 0)
++                {
++                    (*reply_number)++;
++                    break;
++                }
++                /*endif*/
++            }
++            /*endfor*/
++        }
++        /*endfor*/
++    }
++    /*endif*/
++
++    if (!(*reply_number))
++        return NULL;
++    /*endif*/
++    ext_list = (XIMExt *) malloc (sizeof (XIMExt)*(*reply_number));
++    if (!ext_list)
++        return NULL;
++    /*endif*/
++    memset (ext_list, 0, sizeof (XIMExt)*(*reply_number));
++
++    if (number == 0)
++    {
++        /* query all extensions */
++        for (i = 0;  i < im_ext_len;  i++)
++        {
++            ext_list[i].major_opcode = im_ext[i].major_opcode;
++            ext_list[i].minor_opcode = im_ext[i].minor_opcode;
++            ext_list[i].length = im_ext[i].length;
++            ext_list[i].name = malloc (im_ext[i].length + 1);
++            strcpy (ext_list[i].name, im_ext[i].name);
++        }
++        /*endfor*/
++    }
++    else
++    {
++        int n = 0;
++
++        for (i = 0;  i < im_ext_len;  i++)
++        {
++            for (j = 0;  j < (int)number;  j++)
++            {
++                if (strcmp (lib_extension[j].name, im_ext[i].name) == 0)
++                {
++                    ext_list[n].major_opcode = im_ext[i].major_opcode;
++                    ext_list[n].minor_opcode = im_ext[i].minor_opcode;
++                    ext_list[n].length = im_ext[i].length;
++                    ext_list[n].name = malloc (im_ext[i].length + 1);
++                    strcpy (ext_list[n].name, im_ext[i].name);
++                    n++;
++                    break;
++                }
++                /*endif*/
++            }
++            /*endfor*/
++        }
++        /*endfor*/
++    }
++    /*endif*/
++    return ext_list;
++}
++
++static void QueryExtensionMessageProc (XIMS ims,
++                                       IMProtocol *call_data,
++                                       unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    FmStatus status;
++    extern XimFrameRec query_extension_fr[];
++    extern XimFrameRec query_extension_reply_fr[];
++    unsigned char *reply = NULL;
++    int str_size;
++    register int i;
++    register int number;
++    register int total_size;
++    int byte_length;
++    int reply_number = 0;
++    XIMExt *ext_list;
++    IMQueryExtensionStruct *query_ext =
++        (IMQueryExtensionStruct *) &call_data->queryext;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (query_extension_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, byte_length);
++    query_ext->extension = (XIMStr *) malloc (sizeof (XIMStr)*10);
++    memset (query_ext->extension, 0, sizeof (XIMStr)*10);
++    number = 0;
++    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++    {
++        char *name;
++        int str_length;
++
++        FrameMgrGetToken (fm, str_length);
++        FrameMgrSetSize (fm, str_length);
++        query_ext->extension[number].length = str_length;
++        FrameMgrGetToken (fm, name);
++        query_ext->extension[number].name = malloc (str_length + 1);
++        strncpy (query_ext->extension[number].name, name, str_length);
++        query_ext->extension[number].name[str_length] = (char) 0;
++        number++;
++    }
++    /*endwhile*/
++    query_ext->number = number;
++
++#ifdef PROTOCOL_RICH
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++#endif  /* PROTOCOL_RICH */
++
++    FrameMgrFree (fm);
++
++    ext_list = MakeExtensionList (i18n_core,
++                                  query_ext->extension,
++                                  number,
++                                  &reply_number);
++
++    for (i = 0;  i < number;  i++)
++        XFree (query_ext->extension[i].name);
++    /*endfor*/
++    XFree (query_ext->extension);
++
++    fm = FrameMgrInit (query_extension_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set iteration count for list of extensions */
++    FrameMgrSetIterCount (fm, reply_number);
++
++    /* set length of BARRAY item in ext_fr */
++    for (i = 0;  i < reply_number;  i++)
++    {
++        str_size = strlen (ext_list[i].name);
++        FrameMgrSetSize (fm, str_size);
++    }
++    /*endfor*/
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_ERROR,
++                           0,
++                           0,
++                           0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++
++    for (i = 0;  i < reply_number;  i++)
++    {
++        str_size = FrameMgrGetSize (fm);
++        FrameMgrPutToken (fm, ext_list[i].major_opcode);
++        FrameMgrPutToken (fm, ext_list[i].minor_opcode);
++        FrameMgrPutToken (fm, str_size);
++        FrameMgrPutToken (fm, ext_list[i].name);
++    }
++    /*endfor*/
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_QUERY_EXTENSION_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    for (i = 0;  i < reply_number;  i++)
++        XFree (ext_list[i].name);
++    /*endfor*/
++    XFree ((char *) ext_list);
++}
++
++static void SyncReplyMessageProc (XIMS ims,
++                                  IMProtocol *call_data,
++                                  unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec sync_reply_fr[];
++    CARD16 connect_id = call_data->any.connect_id;
++    Xi18nClient *client;
++    CARD16 input_method_ID;
++    CARD16 input_context_ID;
++
++    client = (Xi18nClient *)_Xi18nFindClient (i18n_core, connect_id);
++    fm = FrameMgrInit (sync_reply_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, input_context_ID);
++    FrameMgrFree (fm);
++
++    client->sync = False;
++
++    if (ims->sync == True) {
++	ims->sync = False;
++	if (i18n_core->address.improto) {
++	    call_data->sync_xlib.major_code = XIM_SYNC_REPLY;
++	    call_data->sync_xlib.minor_code = 0;
++	    call_data->sync_xlib.connect_id = input_method_ID;
++	    call_data->sync_xlib.icid = input_context_ID;
++	    i18n_core->address.improto(ims, call_data);
++	}
++    }
++}
++
++static void GetIMValueFromName (Xi18n i18n_core,
++                                CARD16 connect_id,
++                                char *buf,
++                                char *name,
++                                int *length)
++{
++    register int i;
++
++    if (strcmp (name, XNQueryInputStyle) == 0)
++    {
++        XIMStyles *styles = (XIMStyles *) &i18n_core->address.input_styles;
++
++        *length = sizeof (CARD16)*2; 	/* count_styles, unused */
++        *length += styles->count_styles*sizeof (CARD32);
++
++        if (buf != NULL)
++        {
++            FrameMgr fm;
++            extern XimFrameRec input_styles_fr[];
++            unsigned char *data = NULL;
++            int total_size;
++
++            fm = FrameMgrInit (input_styles_fr,
++                               NULL,
++                               _Xi18nNeedSwap (i18n_core, connect_id));
++
++            /* set iteration count for list of input_style */
++            FrameMgrSetIterCount (fm, styles->count_styles);
++
++            total_size = FrameMgrGetTotalSize (fm);
++            data = (unsigned char *) malloc (total_size);
++            if (!data)
++                return;
++            /*endif*/
++            memset (data, 0, total_size);
++            FrameMgrSetBuffer (fm, data);
++
++            FrameMgrPutToken (fm, styles->count_styles);
++            for (i = 0;  i < (int) styles->count_styles;  i++)
++                FrameMgrPutToken (fm, styles->supported_styles[i]);
++            /*endfor*/
++            memmove (buf, data, total_size);
++            FrameMgrFree (fm);
++
++            /* ADDED BY SUZHE */
++            free (data);
++            /* ADDED BY SUZHE */
++        }
++        /*endif*/
++    }
++    /*endif*/
++
++    else if (strcmp (name, XNQueryIMValuesList) == 0) {
++    }
++}
++
++static XIMAttribute *MakeIMAttributeList (Xi18n i18n_core,
++                                          CARD16 connect_id,
++                                          CARD16 *list,
++                                          int *number,
++                                          int *length)
++{
++    XIMAttribute *attrib_list;
++    int list_num;
++    XIMAttr *attr = i18n_core->address.xim_attr;
++    int list_len = i18n_core->address.im_attr_num;
++    register int i;
++    register int j;
++    int value_length;
++    int number_ret = 0;
++
++    *length = 0;
++    list_num = 0;
++    for (i = 0;  i < *number;  i++)
++    {
++        for (j = 0;  j < list_len;  j++)
++        {
++            if (attr[j].attribute_id == list[i])
++            {
++                list_num++;
++                break;
++            }
++            /*endif*/
++        }
++        /*endfor*/
++    }
++    /*endfor*/
++    attrib_list = (XIMAttribute *) malloc (sizeof (XIMAttribute)*list_num);
++    if (!attrib_list)
++        return NULL;
++    /*endif*/
++    memset (attrib_list, 0, sizeof (XIMAttribute)*list_num);
++    number_ret = list_num;
++    list_num = 0;
++    for (i = 0;  i < *number;  i++)
++    {
++        for (j = 0;  j < list_len;  j++)
++        {
++            if (attr[j].attribute_id == list[i])
++            {
++                attrib_list[list_num].attribute_id = attr[j].attribute_id;
++                attrib_list[list_num].name_length = attr[j].length;
++                attrib_list[list_num].name = attr[j].name;
++                attrib_list[list_num].type = attr[j].type;
++                GetIMValueFromName (i18n_core,
++                                    connect_id,
++                                    NULL,
++                                    attr[j].name,
++                                    &value_length);
++                attrib_list[list_num].value_length = value_length;
++                attrib_list[list_num].value = (void *) malloc (value_length);
++                memset(attrib_list[list_num].value, 0, value_length);
++                GetIMValueFromName (i18n_core,
++                                    connect_id,
++                                    attrib_list[list_num].value,
++                                    attr[j].name,
++                                    &value_length);
++                *length += sizeof (CARD16)*2;
++                *length += value_length;
++                *length += IMPAD (value_length);
++                list_num++;
++                break;
++            }
++            /*endif*/
++        }
++        /*endfor*/
++    }
++    /*endfor*/
++    *number = number_ret;
++    return attrib_list;
++}
++
++static void GetIMValuesMessageProc (XIMS ims,
++                                    IMProtocol *call_data,
++                                    unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    FmStatus status;
++    extern XimFrameRec get_im_values_fr[];
++    extern XimFrameRec get_im_values_reply_fr[];
++    CARD16 byte_length;
++    int list_len, total_size;
++    unsigned char *reply = NULL;
++    int iter_count;
++    register int i;
++    register int j;
++    int number;
++    CARD16 *im_attrID_list;
++    char **name_list;
++    CARD16 name_number;
++    XIMAttribute *im_attribute_list;
++    IMGetIMValuesStruct *getim = (IMGetIMValuesStruct *)&call_data->getim;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    /* create FrameMgr */
++    fm = FrameMgrInit (get_im_values_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, byte_length);
++    im_attrID_list = (CARD16 *) malloc (sizeof (CARD16)*20);
++    memset (im_attrID_list, 0, sizeof (CARD16)*20);
++    name_list = (char **)malloc(sizeof(char *) * 20);
++    memset(name_list, 0, sizeof(char *) * 20);
++    number = 0;
++    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++    {
++        FrameMgrGetToken (fm, im_attrID_list[number]);
++        number++;
++    }
++    FrameMgrFree (fm);
++
++    name_number = 0;
++    for (i = 0;  i < number;  i++) {
++        for (j = 0;  j < i18n_core->address.im_attr_num;  j++) {
++            if (i18n_core->address.xim_attr[j].attribute_id ==
++                    im_attrID_list[i]) {
++                name_list[name_number++] =
++			i18n_core->address.xim_attr[j].name;
++                break;
++            }
++        }
++    }
++    getim->number = name_number;
++    getim->im_attr_list = name_list;
++    XFree (name_list);
++
++
++#ifdef PROTOCOL_RICH
++    if (i18n_core->address.improto) {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++    }
++#endif  /* PROTOCOL_RICH */
++
++    im_attribute_list = MakeIMAttributeList (i18n_core,
++                                             connect_id,
++                                             im_attrID_list,
++                                             &number,
++                                             &list_len);
++    if (im_attrID_list)
++        XFree (im_attrID_list);
++    /*endif*/
++
++    fm = FrameMgrInit (get_im_values_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    iter_count = number;
++
++    /* set iteration count for list of im_attribute */
++    FrameMgrSetIterCount (fm, iter_count);
++
++    /* set length of BARRAY item in ximattribute_fr */
++    for (i = 0;  i < iter_count;  i++)
++        FrameMgrSetSize (fm, im_attribute_list[i].value_length);
++    /*endfor*/
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++
++    for (i = 0;  i < iter_count;  i++)
++    {
++        FrameMgrPutToken (fm, im_attribute_list[i].attribute_id);
++        FrameMgrPutToken (fm, im_attribute_list[i].value_length);
++        FrameMgrPutToken (fm, im_attribute_list[i].value);
++    }
++    /*endfor*/
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_GET_IM_VALUES_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree (reply);
++
++    for (i = 0; i < iter_count; i++)
++        XFree(im_attribute_list[i].value);
++    XFree (im_attribute_list);
++}
++
++static void CreateICMessageProc (XIMS ims,
++                                 IMProtocol *call_data,
++                                 unsigned char *p)
++{
++    _Xi18nChangeIC (ims, call_data, p, True);
++}
++
++static void SetICValuesMessageProc (XIMS ims,
++                                    IMProtocol *call_data,
++                                    unsigned char *p)
++{
++    _Xi18nChangeIC (ims, call_data, p, False);
++}
++
++static void GetICValuesMessageProc (XIMS ims,
++                                    IMProtocol *call_data,
++                                    unsigned char *p)
++{
++    _Xi18nGetIC (ims, call_data, p);
++}
++
++static void SetICFocusMessageProc (XIMS ims,
++                                   IMProtocol *call_data,
++                                   unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec set_ic_focus_fr[];
++    IMChangeFocusStruct *setfocus;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    /* some buggy xim clients do not send XIM_SYNC_REPLY for synchronous
++     * events. In such case, xim server is waiting for XIM_SYNC_REPLY
++     * forever. So the xim server is blocked to waiting sync reply.
++     * It prevents further input.
++     * Usually it happens when a client calls XSetICFocus() with another ic
++     * before passing an event to XFilterEvent(), where the event is needed
++     * by the old focused ic to sync its state.
++     * To avoid such problem, remove the whole clients queue and set them
++     * as asynchronous.
++     *
++     * See:
++     * http://bugs.freedesktop.org/show_bug.cgi?id=7869
++     */
++    DiscardAllQueue(ims);
++
++    setfocus = (IMChangeFocusStruct *) &call_data->changefocus;
++
++    fm = FrameMgrInit (set_ic_focus_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, setfocus->icid);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++static void UnsetICFocusMessageProc (XIMS ims,
++                                     IMProtocol *call_data,
++                                     unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec unset_ic_focus_fr[];
++    IMChangeFocusStruct *unsetfocus;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
++
++    /* some buggy clients unset focus ic before the ic answer the sync reply,
++     * so the xim server may be blocked to waiting sync reply. To avoid
++     * this problem, remove the client queue and set it asynchronous
++     *
++     * See: SetICFocusMessageProc
++     */
++    if (client != NULL && client->sync) {
++	DiscardQueue(ims, client->connect_id);
++    }
++
++    unsetfocus = (IMChangeFocusStruct *) &call_data->changefocus;
++
++    fm = FrameMgrInit (unset_ic_focus_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, unsetfocus->icid);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++static void DestroyICMessageProc (XIMS ims,
++                                  IMProtocol *call_data,
++                                  unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec destroy_ic_fr[];
++    extern XimFrameRec destroy_ic_reply_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMDestroyICStruct *destroy =
++        (IMDestroyICStruct *) &call_data->destroyic;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (destroy_ic_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, destroy->icid);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++
++    fm = FrameMgrInit (destroy_ic_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, destroy->icid);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_DESTROY_IC_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    XFree(reply);
++    FrameMgrFree (fm);
++}
++
++static void ResetICMessageProc (XIMS ims,
++                                IMProtocol *call_data,
++                                unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec reset_ic_fr[];
++    extern XimFrameRec reset_ic_reply_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMResetICStruct *resetic =
++        (IMResetICStruct *) &call_data->resetic;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (reset_ic_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, resetic->icid);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++
++    /* create FrameMgr */
++    fm = FrameMgrInit (reset_ic_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set length of STRING8 */
++    FrameMgrSetSize (fm, resetic->length);
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, resetic->icid);
++    FrameMgrPutToken(fm, resetic->length);
++    FrameMgrPutToken (fm, resetic->commit_string);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_RESET_IC_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree(reply);
++}
++
++static int WireEventToEvent (Xi18n i18n_core,
++                             xEvent *event,
++                             CARD16 serial,
++                             XEvent *ev,
++                             Bool byte_swap)
++{
++    FrameMgr fm;
++    extern XimFrameRec wire_keyevent_fr[];
++    BYTE b;
++    CARD16 c16;
++    CARD32 c32;
++    int ret = False;
++
++    /* create FrameMgr */
++    fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
++
++
++    /* get & set type */
++    FrameMgrGetToken(fm, b);
++    ev->type = (unsigned int)b;
++    /* get detail */
++    FrameMgrGetToken(fm, b);
++    /* get & set serial */
++    FrameMgrGetToken(fm, c16);
++    ev->xany.serial = (unsigned long)c16;
++    ev->xany.serial |= serial << 16;
++    ev->xany.send_event = False;
++    ev->xany.display = i18n_core->address.dpy;
++
++    /* Remove SendEvent flag from event type to emulate KeyPress/Release */
++    ev->type &= 0x7F;
++
++    switch (ev->type) {
++      case KeyPress:
++      case KeyRelease:
++      {
++          XKeyEvent *kev = (XKeyEvent*)ev;
++
++          /* set keycode (detail) */
++          kev->keycode = (unsigned int)b;
++
++          /* get & set values */
++          FrameMgrGetToken(fm, c32); kev->time = (Time)c32;
++          FrameMgrGetToken(fm, c32); kev->root = (Window)c32;
++          FrameMgrGetToken(fm, c32); kev->window = (Window)c32;
++          FrameMgrGetToken(fm, c32); kev->subwindow = (Window)c32;
++          FrameMgrGetToken(fm, c16); kev->x_root = (int)c16;
++          FrameMgrGetToken(fm, c16); kev->y_root = (int)c16;
++          FrameMgrGetToken(fm, c16); kev->x = (int)c16;
++          FrameMgrGetToken(fm, c16); kev->y = (int)c16;
++          FrameMgrGetToken(fm, c16); kev->state = (unsigned int)c16;
++          FrameMgrGetToken(fm, b);   kev->same_screen = (Bool)b;
++      }
++      ret = True;
++      break;
++      default:
++      break;
++    }
++    /* free FrameMgr */
++    FrameMgrFree(fm);
++    return ret;
++}
++
++static void ForwardEventMessageProc (XIMS ims,
++                                     IMProtocol *call_data,
++                                     unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec forward_event_fr[];
++    xEvent wire_event;
++    IMForwardEventStruct *forward =
++        (IMForwardEventStruct*) &call_data->forwardevent;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (forward_event_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, forward->icid);
++    FrameMgrGetToken (fm, forward->sync_bit);
++    FrameMgrGetToken (fm, forward->serial_number);
++    p += sizeof (CARD16)*4;
++    memmove (&wire_event, p, sizeof (xEvent));
++
++    FrameMgrFree (fm);
++
++    if (WireEventToEvent (i18n_core,
++                          &wire_event,
++                          forward->serial_number,
++                          &forward->event,
++			  _Xi18nNeedSwap (i18n_core, connect_id)) == True)
++    {
++        if (i18n_core->address.improto)
++        {
++            if (!(i18n_core->address.improto(ims, call_data)))
++                return;
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endif*/
++}
++
++static void ExtForwardKeyEventMessageProc (XIMS ims,
++                                           IMProtocol *call_data,
++                                           unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec ext_forward_keyevent_fr[];
++    CARD8 type, keycode;
++    CARD16 state;
++    CARD32 ev_time, window;
++    IMForwardEventStruct *forward =
++        (IMForwardEventStruct *) &call_data->forwardevent;
++    XEvent *ev = (XEvent *) &forward->event;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (ext_forward_keyevent_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, forward->icid);
++    FrameMgrGetToken (fm, forward->sync_bit);
++    FrameMgrGetToken (fm, forward->serial_number);
++    FrameMgrGetToken (fm, type);
++    FrameMgrGetToken (fm, keycode);
++    FrameMgrGetToken (fm, state);
++    FrameMgrGetToken (fm, ev_time);
++    FrameMgrGetToken (fm, window);
++
++    FrameMgrFree (fm);
++
++    if (type != KeyPress)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++
++    /* make a faked keypress event */
++    ev->type = (int)type;
++    ev->xany.send_event = True;
++    ev->xany.display = i18n_core->address.dpy;
++    ev->xany.serial = (unsigned long) forward->serial_number;
++    ((XKeyEvent *) ev)->keycode = (unsigned int) keycode;
++    ((XKeyEvent *) ev)->state = (unsigned int) state;
++    ((XKeyEvent *) ev)->time = (Time) ev_time;
++    ((XKeyEvent *) ev)->window = (Window) window;
++    ((XKeyEvent *) ev)->root = DefaultRootWindow (ev->xany.display);
++    ((XKeyEvent *) ev)->x = 0;
++    ((XKeyEvent *) ev)->y = 0;
++    ((XKeyEvent *) ev)->x_root = 0;
++    ((XKeyEvent *) ev)->y_root = 0;
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++static void ExtMoveMessageProc (XIMS ims,
++                                IMProtocol *call_data,
++                                unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec ext_move_fr[];
++    IMMoveStruct *extmove =
++        (IMMoveStruct*) & call_data->extmove;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (ext_move_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, extmove->icid);
++    FrameMgrGetToken (fm, extmove->x);
++    FrameMgrGetToken (fm, extmove->y);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++static void ExtensionMessageProc (XIMS ims,
++                                  IMProtocol *call_data,
++                                  unsigned char *p)
++{
++    switch (call_data->any.minor_code)
++    {
++    case XIM_EXT_FORWARD_KEYEVENT:
++        ExtForwardKeyEventMessageProc (ims, call_data, p);
++        break;
++
++    case XIM_EXT_MOVE:
++        ExtMoveMessageProc (ims, call_data, p);
++        break;
++    }
++    /*endswitch*/
++}
++
++static void TriggerNotifyMessageProc (XIMS ims,
++                                      IMProtocol *call_data,
++                                      unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec trigger_notify_fr[], trigger_notify_reply_fr[];
++    register int total_size;
++    unsigned char *reply = NULL;
++    IMTriggerNotifyStruct *trigger =
++        (IMTriggerNotifyStruct *) &call_data->triggernotify;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++    CARD32 flag;
++
++    fm = FrameMgrInit (trigger_notify_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, trigger->icid);
++    FrameMgrGetToken (fm, trigger->flag);
++    FrameMgrGetToken (fm, trigger->key_index);
++    FrameMgrGetToken (fm, trigger->event_mask);
++    /*
++      In order to support Front End Method, this event_mask must be saved
++      per clients so that it should be restored by an XIM_EXT_SET_EVENT_MASK
++      call when preediting mode is reset to off.
++     */
++
++    flag = trigger->flag;
++
++    FrameMgrFree (fm);
++
++    fm = FrameMgrInit (trigger_notify_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, trigger->icid);
++
++    /* NOTE:
++       XIM_TRIGGER_NOTIFY_REPLY should be sent before XIM_SET_EVENT_MASK
++       in case of XIM_TRIGGER_NOTIFY(flag == ON), while it should be
++       sent after XIM_SET_EVENT_MASK in case of
++       XIM_TRIGGER_NOTIFY(flag == OFF).
++       */
++    if (flag == 0)
++    {
++        /* on key */
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_TRIGGER_NOTIFY_REPLY,
++                           0,
++                           reply,
++                           total_size);
++        IMPreeditStart (ims, (XPointer)call_data);
++    }
++    /*endif*/
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++
++    if (flag == 1)
++    {
++        /* off key */
++        IMPreeditEnd (ims, (XPointer) call_data);
++        _Xi18nSendMessage (ims,
++                           connect_id,
++                           XIM_TRIGGER_NOTIFY_REPLY,
++                           0,
++                           reply,
++                           total_size);
++    }
++    /*endif*/
++    FrameMgrFree (fm);
++    XFree (reply);
++}
++
++static INT16 ChooseEncoding (Xi18n i18n_core,
++                             IMEncodingNegotiationStruct *enc_nego)
++{
++    Xi18nAddressRec *address = (Xi18nAddressRec *) & i18n_core->address;
++    XIMEncodings *p;
++    int i, j;
++    int enc_index=0;
++
++    p = (XIMEncodings *) &address->encoding_list;
++    for (i = 0;  i < (int) p->count_encodings;  i++)
++    {
++        for (j = 0;  j < (int) enc_nego->encoding_number;  j++)
++        {
++            if (strcmp (p->supported_encodings[i],
++                        enc_nego->encoding[j].name) == 0)
++            {
++                enc_index = j;
++                break;
++            }
++            /*endif*/
++        }
++        /*endfor*/
++    }
++    /*endfor*/
++
++    return (INT16) enc_index;
++#if 0
++    return (INT16) XIM_Default_Encoding_IDX;
++#endif
++}
++
++static void EncodingNegotiatonMessageProc (XIMS ims,
++                                           IMProtocol *call_data,
++                                           unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    FmStatus status;
++    CARD16 byte_length;
++    extern XimFrameRec encoding_negotiation_fr[];
++    extern XimFrameRec encoding_negotiation_reply_fr[];
++    register int i, total_size;
++    unsigned char *reply = NULL;
++    IMEncodingNegotiationStruct *enc_nego =
++        (IMEncodingNegotiationStruct *) &call_data->encodingnego;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (encoding_negotiation_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    FrameMgrGetToken (fm, input_method_ID);
++
++    /* get ENCODING STR field */
++    FrameMgrGetToken (fm, byte_length);
++    if (byte_length > 0)
++    {
++        enc_nego->encoding = (XIMStr *) malloc (sizeof (XIMStr)*10);
++        memset (enc_nego->encoding, 0, sizeof (XIMStr)*10);
++        i = 0;
++        while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++        {
++            char *name;
++            int str_length;
++
++            FrameMgrGetToken (fm, str_length);
++            FrameMgrSetSize (fm, str_length);
++            enc_nego->encoding[i].length = str_length;
++            FrameMgrGetToken (fm, name);
++            enc_nego->encoding[i].name = malloc (str_length + 1);
++            strncpy (enc_nego->encoding[i].name, name, str_length);
++            enc_nego->encoding[i].name[str_length] = '\0';
++            i++;
++        }
++        /*endwhile*/
++        enc_nego->encoding_number = i;
++    }
++    /*endif*/
++    /* get ENCODING INFO field */
++    FrameMgrGetToken (fm, byte_length);
++    if (byte_length > 0)
++    {
++        enc_nego->encodinginfo = (XIMStr *) malloc (sizeof (XIMStr)*10);
++        memset (enc_nego->encoding, 0, sizeof (XIMStr)*10);
++        i = 0;
++        while (FrameMgrIsIterLoopEnd (fm, &status) == False)
++        {
++            char *name;
++            int str_length;
++
++            FrameMgrGetToken (fm, str_length);
++            FrameMgrSetSize (fm, str_length);
++            enc_nego->encodinginfo[i].length = str_length;
++            FrameMgrGetToken (fm, name);
++            enc_nego->encodinginfo[i].name = malloc (str_length + 1);
++            strncpy (enc_nego->encodinginfo[i].name, name, str_length);
++            enc_nego->encodinginfo[i].name[str_length] = '\0';
++            i++;
++        }
++        /*endwhile*/
++        enc_nego->encoding_info_number = i;
++    }
++    /*endif*/
++
++    enc_nego->enc_index = ChooseEncoding (i18n_core, enc_nego);
++    enc_nego->category = 0;
++
++#ifdef PROTOCOL_RICH
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++#endif  /* PROTOCOL_RICH */
++
++    FrameMgrFree (fm);
++
++    fm = FrameMgrInit (encoding_negotiation_reply_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, input_method_ID);
++    FrameMgrPutToken (fm, enc_nego->category);
++    FrameMgrPutToken (fm, enc_nego->enc_index);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_ENCODING_NEGOTIATION_REPLY,
++                       0,
++                       reply,
++                       total_size);
++    XFree (reply);
++
++    /* free data for encoding list */
++    if (enc_nego->encoding)
++    {
++        for (i = 0;  i < (int) enc_nego->encoding_number;  i++)
++            XFree (enc_nego->encoding[i].name);
++        /*endfor*/
++        XFree (enc_nego->encoding);
++    }
++    /*endif*/
++    if (enc_nego->encodinginfo)
++    {
++        for (i = 0;  i < (int) enc_nego->encoding_info_number;  i++)
++            XFree (enc_nego->encodinginfo[i].name);
++        /*endfor*/
++        XFree (enc_nego->encodinginfo);
++    }
++    /*endif*/
++    FrameMgrFree (fm);
++}
++
++void PreeditStartReplyMessageProc (XIMS ims,
++                                   IMProtocol *call_data,
++                                   unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_start_reply_fr[];
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct *) &call_data->preedit_callback;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (preedit_start_reply_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, preedit_CB->icid);
++    FrameMgrGetToken (fm, preedit_CB->todo.return_value);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto (ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++void PreeditCaretReplyMessageProc (XIMS ims,
++                                   IMProtocol *call_data,
++                                   unsigned char *p)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec preedit_caret_reply_fr[];
++    IMPreeditCBStruct *preedit_CB =
++        (IMPreeditCBStruct *) &call_data->preedit_callback;
++    XIMPreeditCaretCallbackStruct *caret =
++        (XIMPreeditCaretCallbackStruct *) & preedit_CB->todo.caret;
++    CARD16 connect_id = call_data->any.connect_id;
++    CARD16 input_method_ID;
++
++    fm = FrameMgrInit (preedit_caret_reply_fr,
++                       (char *) p,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++    /* get data */
++    FrameMgrGetToken (fm, input_method_ID);
++    FrameMgrGetToken (fm, preedit_CB->icid);
++    FrameMgrGetToken (fm, caret->position);
++
++    FrameMgrFree (fm);
++
++    if (i18n_core->address.improto)
++    {
++        if (!(i18n_core->address.improto(ims, call_data)))
++            return;
++        /*endif*/
++    }
++    /*endif*/
++}
++
++void StrConvReplyMessageProc (XIMS ims,
++                              IMProtocol *call_data,
++                              unsigned char *p)
++{
++    return;
++}
++
++static void AddQueue (Xi18nClient *client, unsigned char *p)
++{
++    XIMPending *new;
++    XIMPending *last;
++
++    if ((new = (XIMPending *) malloc (sizeof (XIMPending))) == NULL)
++        return;
++    /*endif*/
++    new->p = p;
++    new->next = (XIMPending *) NULL;
++    if (!client->pending)
++    {
++        client->pending = new;
++    }
++    else
++    {
++        for (last = client->pending;  last->next;  last = last->next)
++            ;
++        /*endfor*/
++        last->next = new;
++    }
++    /*endif*/
++    return;
++}
++
++static void ProcessQueue (XIMS ims, CARD16 connect_id)
++{
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient *client = (Xi18nClient *) _Xi18nFindClient (i18n_core,
++                                                            connect_id);
++
++    while (client->sync == False  &&  client->pending)
++    {
++        XimProtoHdr *hdr = (XimProtoHdr *) client->pending->p;
++        unsigned char *p1 = (unsigned char *) (hdr + 1);
++        IMProtocol call_data;
++
++        call_data.major_code = hdr->major_opcode;
++        call_data.any.minor_code = hdr->minor_opcode;
++        call_data.any.connect_id = connect_id;
++
++        switch (hdr->major_opcode)
++        {
++        case XIM_FORWARD_EVENT:
++            ForwardEventMessageProc(ims, &call_data, p1);
++            break;
++        }
++        /*endswitch*/
++        XFree (hdr);
++        {
++            XIMPending *old = client->pending;
++
++            client->pending = old->next;
++            XFree (old);
++        }
++    }
++    /*endwhile*/
++    return;
++}
++
++
++void _Xi18nMessageHandler (XIMS ims,
++                           CARD16 connect_id,
++                           unsigned char *p,
++                           Bool *delete)
++{
++    XimProtoHdr	*hdr = (XimProtoHdr *)p;
++    unsigned char *p1 = (unsigned char *)(hdr + 1);
++    IMProtocol call_data;
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient *client;
++
++    client = (Xi18nClient *) _Xi18nFindClient (i18n_core, connect_id);
++    if (hdr == (XimProtoHdr *) NULL)
++        return;
++    /*endif*/
++
++    memset (&call_data, 0, sizeof(IMProtocol));
++
++    call_data.major_code = hdr->major_opcode;
++    call_data.any.minor_code = hdr->minor_opcode;
++    call_data.any.connect_id = connect_id;
++
++    switch (call_data.major_code)
++    {
++    case XIM_CONNECT:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_CONNECT\n");
++#endif
++        ConnectMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_DISCONNECT:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_DISCONNECT\n");
++#endif
++        DisConnectMessageProc (ims, &call_data);
++        break;
++
++    case XIM_OPEN:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_OPEN\n");
++#endif
++        OpenMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_CLOSE:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_CLOSE\n");
++#endif
++        CloseMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_QUERY_EXTENSION:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_QUERY_EXTENSION\n");
++#endif
++        QueryExtensionMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_GET_IM_VALUES:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_GET_IM_VALUES\n");
++#endif
++        GetIMValuesMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_CREATE_IC:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_CREATE_IC\n");
++#endif
++        CreateICMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_SET_IC_VALUES:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_SET_IC_VALUES\n");
++#endif
++        SetICValuesMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_GET_IC_VALUES:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_GET_IC_VALUES\n");
++#endif
++        GetICValuesMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_SET_IC_FOCUS:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_SET_IC_FOCUS\n");
++#endif
++        SetICFocusMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_UNSET_IC_FOCUS:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_UNSET_IC_FOCUS\n");
++#endif
++        UnsetICFocusMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_DESTROY_IC:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_DESTROY_IC\n");
++#endif
++        DestroyICMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_RESET_IC:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_RESET_IC\n");
++#endif
++        ResetICMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_FORWARD_EVENT:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_FORWARD_EVENT\n");
++#endif
++        if (client->sync == True)
++        {
++            AddQueue (client, p);
++            *delete = False;
++        }
++        else
++        {
++            ForwardEventMessageProc (ims, &call_data, p1);
++        }
++        break;
++
++    case XIM_EXTENSION:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_EXTENSION\n");
++#endif
++        ExtensionMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_SYNC:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_SYNC\n");
++#endif
++        break;
++
++    case XIM_SYNC_REPLY:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_SYNC_REPLY\n");
++#endif
++        SyncReplyMessageProc (ims, &call_data, p1);
++        ProcessQueue (ims, connect_id);
++        break;
++
++    case XIM_TRIGGER_NOTIFY:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_TRIGGER_NOTIFY\n");
++#endif
++        TriggerNotifyMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_ENCODING_NEGOTIATION:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_ENCODING_NEGOTIATION\n");
++#endif
++        EncodingNegotiatonMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_PREEDIT_START_REPLY:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_PREEDIT_START_REPLY\n");
++#endif
++        PreeditStartReplyMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_PREEDIT_CARET_REPLY:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_PREEDIT_CARET_REPLY\n");
++#endif
++        PreeditCaretReplyMessageProc (ims, &call_data, p1);
++        break;
++
++    case XIM_STR_CONVERSION_REPLY:
++#ifdef XIM_DEBUG
++	DebugLog("-- XIM_STR_CONVERSION_REPLY\n");
++#endif
++        StrConvReplyMessageProc (ims, &call_data, p1);
++        break;
++    }
++    /*endswitch*/
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nUtil.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nUtil.c
+new file mode 100644
+index 0000000..ff8970e
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nUtil.c
+@@ -0,0 +1,276 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "FrameMgr.h"
++#include "XimFunc.h"
++
++Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
++
++int
++_Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id)
++{
++    CARD8 im_byteOrder = i18n_core->address.im_byteOrder;
++    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
++
++    return (client->byte_order != im_byteOrder);
++}
++
++Xi18nClient *_Xi18nNewClient(Xi18n i18n_core)
++{
++    static CARD16 connect_id = 0;
++    int new_connect_id;
++    Xi18nClient *client;
++
++    if (i18n_core->address.free_clients)
++    {
++        client = i18n_core->address.free_clients;
++        i18n_core->address.free_clients = client->next;
++	new_connect_id = client->connect_id;
++    }
++    else
++    {
++        client = (Xi18nClient *) malloc (sizeof (Xi18nClient));
++	new_connect_id = ++connect_id;
++    }
++    /*endif*/
++    memset (client, 0, sizeof (Xi18nClient));
++    client->connect_id = new_connect_id;
++    client->pending = (XIMPending *) NULL;
++    client->sync = False;
++    client->byte_order = '?'; 	/* initial value */
++    memset (&client->pending, 0, sizeof (XIMPending *));
++    client->next = i18n_core->address.clients;
++    i18n_core->address.clients = client;
++
++    return (Xi18nClient *) client;
++}
++
++Xi18nClient *_Xi18nFindClient (Xi18n i18n_core, CARD16 connect_id)
++{
++    Xi18nClient *client = i18n_core->address.clients;
++
++    while (client)
++    {
++        if (client->connect_id == connect_id)
++            return client;
++        /*endif*/
++        client = client->next;
++    }
++    /*endwhile*/
++    return NULL;
++}
++
++void _Xi18nDeleteClient (Xi18n i18n_core, CARD16 connect_id)
++{
++    Xi18nClient *target = _Xi18nFindClient (i18n_core, connect_id);
++    Xi18nClient *ccp;
++    Xi18nClient *ccp0;
++
++    for (ccp = i18n_core->address.clients, ccp0 = NULL;
++         ccp != NULL;
++         ccp0 = ccp, ccp = ccp->next)
++    {
++        if (ccp == target)
++        {
++            if (ccp0 == NULL)
++                i18n_core->address.clients = ccp->next;
++            else
++                ccp0->next = ccp->next;
++            /*endif*/
++            /* put it back to free list */
++            target->next = i18n_core->address.free_clients;
++            i18n_core->address.free_clients = target;
++            return;
++        }
++        /*endif*/
++    }
++    /*endfor*/
++}
++
++void _Xi18nSendMessage (XIMS ims,
++                        CARD16 connect_id,
++                        CARD8 major_opcode,
++                        CARD8 minor_opcode,
++                        unsigned char *data,
++                        long length)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec packet_header_fr[];
++    unsigned char *reply_hdr = NULL;
++    int header_size;
++    unsigned char *reply = NULL;
++    unsigned char *replyp;
++    int reply_length;
++    long p_len = length/4;
++
++    fm = FrameMgrInit (packet_header_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    header_size = FrameMgrGetTotalSize (fm);
++    reply_hdr = (unsigned char *) malloc (header_size);
++    if (reply_hdr == NULL)
++    {
++        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
++        return;
++    }
++    /*endif*/
++    FrameMgrSetBuffer (fm, reply_hdr);
++
++    /* put data */
++    FrameMgrPutToken (fm, major_opcode);
++    FrameMgrPutToken (fm, minor_opcode);
++    FrameMgrPutToken (fm, p_len);
++
++    reply_length = header_size + length;
++    reply = (unsigned char *) malloc (reply_length);
++    replyp = reply;
++    memmove (reply, reply_hdr, header_size);
++    replyp += header_size;
++    memmove (replyp, data, length);
++
++    i18n_core->methods.send (ims, connect_id, reply, reply_length);
++
++    XFree (reply);
++    XFree (reply_hdr);
++    FrameMgrFree (fm);
++}
++
++void _Xi18nSendTriggerKey (XIMS ims, CARD16 connect_id)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec register_triggerkeys_fr[];
++    XIMTriggerKey *on_keys = i18n_core->address.on_keys.keylist;
++    XIMTriggerKey *off_keys = i18n_core->address.off_keys.keylist;
++    int on_key_num = i18n_core->address.on_keys.count_keys;
++    int off_key_num = i18n_core->address.off_keys.count_keys;
++    unsigned char *reply = NULL;
++    register int i, total_size;
++    CARD16 im_id;
++
++    if (on_key_num == 0  &&  off_key_num == 0)
++        return;
++    /*endif*/
++
++    fm = FrameMgrInit (register_triggerkeys_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    /* set iteration count for on-keys list */
++    FrameMgrSetIterCount (fm, on_key_num);
++    /* set iteration count for off-keys list */
++    FrameMgrSetIterCount (fm, off_key_num);
++
++    /* get total_size */
++    total_size = FrameMgrGetTotalSize (fm);
++
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++        return;
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    /* Right now XIM_OPEN_REPLY hasn't been sent to this new client, so
++       the input-method-id is still invalid, and should be set to zero...
++       Reter to $(XC)/lib/X11/imDefLkup.c:_XimRegisterTriggerKeysCallback
++     */
++    im_id = 0;
++    FrameMgrPutToken (fm, im_id);  /* input-method-id */
++    for (i = 0;  i < on_key_num;  i++)
++    {
++        FrameMgrPutToken (fm, on_keys[i].keysym);
++        FrameMgrPutToken (fm, on_keys[i].modifier);
++        FrameMgrPutToken (fm, on_keys[i].modifier_mask);
++    }
++    /*endfor*/
++    for (i = 0;  i < off_key_num;  i++)
++    {
++        FrameMgrPutToken (fm, off_keys[i].keysym);
++        FrameMgrPutToken (fm, off_keys[i].modifier);
++        FrameMgrPutToken (fm, off_keys[i].modifier_mask);
++    }
++    /*endfor*/
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_REGISTER_TRIGGERKEYS,
++                       0,
++                       reply,
++                       total_size);
++    FrameMgrFree (fm);
++    XFree(reply);
++}
++
++void _Xi18nSetEventMask (XIMS ims,
++                         CARD16 connect_id,
++                         CARD16 im_id,
++                         CARD16 ic_id,
++                         CARD32 forward_mask,
++                         CARD32 sync_mask)
++{
++    Xi18n i18n_core = ims->protocol;
++    FrameMgr fm;
++    extern XimFrameRec set_event_mask_fr[];
++    unsigned char *reply = NULL;
++    register int total_size;
++
++    fm = FrameMgrInit (set_event_mask_fr,
++                       NULL,
++                       _Xi18nNeedSwap (i18n_core, connect_id));
++
++    total_size = FrameMgrGetTotalSize (fm);
++    reply = (unsigned char *) malloc (total_size);
++    if (!reply)
++        return;
++    /*endif*/
++    memset (reply, 0, total_size);
++    FrameMgrSetBuffer (fm, reply);
++
++    FrameMgrPutToken (fm, im_id); 	/* input-method-id */
++    FrameMgrPutToken (fm, ic_id); 	/* input-context-id */
++    FrameMgrPutToken (fm, forward_mask);
++    FrameMgrPutToken (fm, sync_mask);
++
++    _Xi18nSendMessage (ims,
++                       connect_id,
++                       XIM_SET_EVENT_MASK,
++                       0,
++                       reply,
++                       total_size);
++
++    FrameMgrFree (fm);
++    XFree(reply);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nX.c b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nX.c
+new file mode 100644
+index 0000000..87df6b4
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/IMdkit/lib/i18nX.c
+@@ -0,0 +1,497 @@
++/******************************************************************
++
++         Copyright 1994, 1995 by Sun Microsystems, Inc.
++         Copyright 1993, 1994 by Hewlett-Packard Company
++
++Permission to use, copy, modify, distribute, and sell this software
++and its documentation for any purpose is hereby granted without fee,
++provided that the above copyright notice appear in all copies and
++that both that copyright notice and this permission notice appear
++in supporting documentation, and that the name of Sun Microsystems, Inc.
++and Hewlett-Packard not be used in advertising or publicity pertaining to
++distribution of the software without specific, written prior permission.
++Sun Microsystems, Inc. and Hewlett-Packard make no representations about
++the suitability of this software for any purpose.  It is provided "as is"
++without express or implied warranty.
++
++SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
++SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
++SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
++RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
++CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
++
++    This version tidied and debugged by Steve Underwood May 1999
++
++******************************************************************/
++
++#include <X11/Xlib.h>
++#include <X11/Xatom.h>
++#include "FrameMgr.h"
++#include "../include/IMdkit.h"
++#include "../include/Xi18n.h"
++#include "Xi18nX.h"
++#include "XimFunc.h"
++
++extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
++extern Xi18nClient *_Xi18nNewClient(Xi18n);
++extern void _Xi18nDeleteClient(Xi18n, CARD16);
++static Bool WaitXConnectMessage(Display*, Window,
++                                XEvent*, XPointer);
++static Bool WaitXIMProtocol(Display*, Window, XEvent*, XPointer);
++
++static XClient *NewXClient (Xi18n i18n_core, Window new_client)
++{
++    Display *dpy = i18n_core->address.dpy;
++    Xi18nClient *client = _Xi18nNewClient (i18n_core);
++    XClient *x_client;
++
++    x_client = (XClient *) malloc (sizeof (XClient));
++    x_client->client_win = new_client;
++    x_client->accept_win = XCreateSimpleWindow (dpy,
++                                                DefaultRootWindow(dpy),
++                                                0,
++                                                0,
++                                                1,
++                                                1,
++                                                1,
++                                                0,
++                                                0);
++    client->trans_rec = x_client;
++    return ((XClient *) x_client);
++}
++
++static unsigned char *ReadXIMMessage (XIMS ims,
++                                      XClientMessageEvent *ev,
++                                      int *connect_id)
++{
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient *client = i18n_core->address.clients;
++    XClient *x_client = NULL;
++    FrameMgr fm;
++    extern XimFrameRec packet_header_fr[];
++    unsigned char *p = NULL;
++    unsigned char *p1;
++
++    while (client != NULL) {
++        x_client = (XClient *) client->trans_rec;
++        if (x_client->accept_win == ev->window) {
++            *connect_id = client->connect_id;
++            break;
++        }
++        client = client->next;
++    }
++
++    if (ev->format == 8) {
++        /* ClientMessage only */
++        XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
++        unsigned char *rec = (unsigned char *) (hdr + 1);
++        register int total_size;
++        CARD8 major_opcode;
++        CARD8 minor_opcode;
++        CARD16 length;
++        extern int _Xi18nNeedSwap (Xi18n, CARD16);
++
++        if (client->byte_order == '?')
++        {
++            if (hdr->major_opcode != XIM_CONNECT)
++                return (unsigned char *) NULL; 	/* can do nothing */
++            client->byte_order = (CARD8) rec[0];
++        }
++
++        fm = FrameMgrInit (packet_header_fr,
++                           (char *) hdr,
++                           _Xi18nNeedSwap (i18n_core, *connect_id));
++        total_size = FrameMgrGetTotalSize (fm);
++        /* get data */
++        FrameMgrGetToken (fm, major_opcode);
++        FrameMgrGetToken (fm, minor_opcode);
++        FrameMgrGetToken (fm, length);
++        FrameMgrFree (fm);
++
++        if ((p = (unsigned char *) malloc (total_size + length * 4)) == NULL)
++            return (unsigned char *) NULL;
++
++        p1 = p;
++        memmove (p1, &major_opcode, sizeof (CARD8));
++        p1 += sizeof (CARD8);
++        memmove (p1, &minor_opcode, sizeof (CARD8));
++        p1 += sizeof (CARD8);
++        memmove (p1, &length, sizeof (CARD16));
++        p1 += sizeof (CARD16);
++        memmove (p1, rec, length * 4);
++    }
++    else if (ev->format == 32) {
++        /* ClientMessage and WindowProperty */
++        unsigned long length = (unsigned long) ev->data.l[0];
++        Atom atom = (Atom) ev->data.l[1];
++        int	return_code;
++        Atom	actual_type_ret;
++        int	actual_format_ret;
++        unsigned long bytes_after_ret;
++        unsigned char *prop;
++        unsigned long nitems;
++
++        return_code = XGetWindowProperty (i18n_core->address.dpy,
++                                          x_client->accept_win,
++                                          atom,
++                                          0L,
++                                          length,
++                                          True,
++                                          AnyPropertyType,
++                                          &actual_type_ret,
++                                          &actual_format_ret,
++                                          &nitems,
++                                          &bytes_after_ret,
++                                          &prop);
++        if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
++            if (return_code == Success)
++                XFree (prop);
++            return (unsigned char *) NULL;
++        }
++        if (length != nitems)
++            length = nitems;
++	if (actual_format_ret == 16)
++	    length *= 2;
++	else if (actual_format_ret == 32)
++	    length *= 4;
++
++        /* if hit, it might be an error */
++        if ((p = (unsigned char *) malloc (length)) == NULL)
++            return (unsigned char *) NULL;
++
++        memmove (p, prop, length);
++        XFree (prop);
++    }
++    return (unsigned char *) p;
++}
++
++static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev)
++{
++    Xi18n i18n_core = ims->protocol;
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++    XEvent event;
++    Display *dpy = i18n_core->address.dpy;
++    Window new_client = ev->data.l[0];
++    CARD32 major_version = ev->data.l[1];
++    CARD32 minor_version = ev->data.l[2];
++    XClient *x_client = NewXClient (i18n_core, new_client);
++
++    if (ev->window != i18n_core->address.im_window)
++        return; 			/* incorrect connection request */
++    /*endif*/
++    if (major_version != 0  ||  minor_version != 0)
++    {
++        major_version =
++        minor_version = 0;
++        /* Only supporting only-CM & Property-with-CM method */
++    }
++    /*endif*/
++    _XRegisterFilterByType (dpy,
++                            x_client->accept_win,
++                            ClientMessage,
++                            ClientMessage,
++                            WaitXIMProtocol,
++                            (XPointer)ims);
++    event.xclient.type = ClientMessage;
++    event.xclient.display = dpy;
++    event.xclient.window = new_client;
++    event.xclient.message_type = spec->connect_request;
++    event.xclient.format = 32;
++    event.xclient.data.l[0] = x_client->accept_win;
++    event.xclient.data.l[1] = major_version;
++    event.xclient.data.l[2] = minor_version;
++    event.xclient.data.l[3] = XCM_DATA_LIMIT;
++
++    XSendEvent (dpy,
++                new_client,
++                False,
++                NoEventMask,
++                &event);
++    XFlush (dpy);
++}
++
++static Bool Xi18nXBegin (XIMS ims)
++{
++    Xi18n i18n_core = ims->protocol;
++    Display *dpy = i18n_core->address.dpy;
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++
++    spec->xim_request = XInternAtom (i18n_core->address.dpy,
++                                     _XIM_PROTOCOL,
++                                     False);
++    spec->connect_request = XInternAtom (i18n_core->address.dpy,
++                                         _XIM_XCONNECT,
++                                         False);
++
++    _XRegisterFilterByType (dpy,
++                            i18n_core->address.im_window,
++                            ClientMessage,
++                            ClientMessage,
++                            WaitXConnectMessage,
++                            (XPointer)ims);
++    return True;
++}
++
++static Bool Xi18nXEnd(XIMS ims)
++{
++    Xi18n i18n_core = ims->protocol;
++    Display *dpy = i18n_core->address.dpy;
++
++    _XUnregisterFilter (dpy,
++                        i18n_core->address.im_window,
++                        WaitXConnectMessage,
++                        (XPointer)ims);
++    return True;
++}
++
++static char *MakeNewAtom (CARD16 connect_id, char *atomName)
++{
++    static int sequence = 0;
++
++    sprintf (atomName,
++             "_server%d_%d",
++             connect_id,
++             ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
++    return atomName;
++}
++
++static Bool Xi18nXSend (XIMS ims,
++                        CARD16 connect_id,
++                        unsigned char *reply,
++                        long length)
++{
++    Xi18n i18n_core = ims->protocol;
++    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++    XClient *x_client = (XClient *) client->trans_rec;
++    XEvent event;
++
++    event.type = ClientMessage;
++    event.xclient.window = x_client->client_win;
++    event.xclient.message_type = spec->xim_request;
++
++    if (length > XCM_DATA_LIMIT)
++    {
++        Atom atom;
++        char atomName[16];
++        Atom actual_type_ret;
++        int actual_format_ret;
++        int return_code;
++        unsigned long nitems_ret;
++        unsigned long bytes_after_ret;
++        unsigned char *win_data;
++
++        event.xclient.format = 32;
++        atom = XInternAtom (i18n_core->address.dpy,
++                            MakeNewAtom (connect_id, atomName),
++                            False);
++        return_code = XGetWindowProperty (i18n_core->address.dpy,
++                                          x_client->client_win,
++                                          atom,
++                                          0L,
++                                          10000L,
++                                          False,
++                                          XA_STRING,
++                                          &actual_type_ret,
++                                          &actual_format_ret,
++                                          &nitems_ret,
++                                          &bytes_after_ret,
++                                          &win_data);
++        if (return_code != Success)
++            return False;
++        /*endif*/
++        if (win_data)
++            XFree ((char *) win_data);
++        /*endif*/
++        XChangeProperty (i18n_core->address.dpy,
++                         x_client->client_win,
++                         atom,
++                         XA_STRING,
++                         8,
++                         PropModeAppend,
++                         (unsigned char *) reply,
++                         length);
++        event.xclient.data.l[0] = length;
++        event.xclient.data.l[1] = atom;
++    }
++    else
++    {
++        unsigned char buffer[XCM_DATA_LIMIT];
++        int i;
++
++        event.xclient.format = 8;
++
++        /* Clear unused field with NULL */
++        memmove(buffer, reply, length);
++        for (i = length; i < XCM_DATA_LIMIT; i++)
++            buffer[i] = (char) 0;
++        /*endfor*/
++        length = XCM_DATA_LIMIT;
++        memmove (event.xclient.data.b, buffer, length);
++    }
++    XSendEvent (i18n_core->address.dpy,
++                x_client->client_win,
++                False,
++                NoEventMask,
++                &event);
++    XFlush (i18n_core->address.dpy);
++    return True;
++}
++
++static Bool CheckCMEvent (Display *display, XEvent *event, XPointer xi18n_core)
++{
++    Xi18n i18n_core = (Xi18n) ((void *) xi18n_core);
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++
++    if ((event->type == ClientMessage)
++        &&
++        (event->xclient.message_type == spec->xim_request))
++    {
++        return  True;
++    }
++    /*endif*/
++    return  False;
++}
++
++static Bool Xi18nXWait (XIMS ims,
++                        CARD16 connect_id,
++                        CARD8 major_opcode,
++                        CARD8 minor_opcode)
++{
++    Xi18n i18n_core = ims->protocol;
++    XEvent event;
++    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
++    XClient *x_client = (XClient *) client->trans_rec;
++
++    for (;;)
++    {
++        unsigned char *packet;
++        XimProtoHdr *hdr;
++        int connect_id_ret;
++
++        XIfEvent (i18n_core->address.dpy,
++                  &event,
++                  CheckCMEvent,
++                  (XPointer) i18n_core);
++        if (event.xclient.window == x_client->accept_win)
++        {
++            if ((packet = ReadXIMMessage (ims,
++                                          (XClientMessageEvent *) & event,
++                                          &connect_id_ret))
++                == (unsigned char*) NULL)
++            {
++                return False;
++            }
++            /*endif*/
++            hdr = (XimProtoHdr *)packet;
++
++            if ((hdr->major_opcode == major_opcode)
++                &&
++                (hdr->minor_opcode == minor_opcode))
++            {
++                return True;
++            }
++            else if (hdr->major_opcode == XIM_ERROR)
++            {
++                return False;
++            }
++            /*endif*/
++        }
++        /*endif*/
++    }
++    /*endfor*/
++}
++
++static Bool Xi18nXDisconnect (XIMS ims, CARD16 connect_id)
++{
++    Xi18n i18n_core = ims->protocol;
++    Display *dpy = i18n_core->address.dpy;
++    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
++    XClient *x_client = (XClient *) client->trans_rec;
++
++    XDestroyWindow (dpy, x_client->accept_win);
++    _XUnregisterFilter (dpy,
++		        x_client->accept_win,
++                        WaitXIMProtocol,
++		        (XPointer)ims);
++    XFree (x_client);
++    _Xi18nDeleteClient (i18n_core, connect_id);
++    return True;
++}
++
++Bool _Xi18nCheckXAddress (Xi18n i18n_core,
++                          TransportSW *transSW,
++                          char *address)
++{
++    XSpecRec *spec;
++
++    if (!(spec = (XSpecRec *) malloc (sizeof (XSpecRec))))
++        return False;
++    /*endif*/
++
++    i18n_core->address.connect_addr = (XSpecRec *) spec;
++    i18n_core->methods.begin = Xi18nXBegin;
++    i18n_core->methods.end = Xi18nXEnd;
++    i18n_core->methods.send = Xi18nXSend;
++    i18n_core->methods.wait = Xi18nXWait;
++    i18n_core->methods.disconnect = Xi18nXDisconnect;
++    return True;
++}
++
++static Bool WaitXConnectMessage (Display *dpy,
++                                 Window win,
++                                 XEvent *ev,
++                                 XPointer client_data)
++{
++    XIMS ims = (XIMS)client_data;
++    Xi18n i18n_core = ims->protocol;
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++
++    if (((XClientMessageEvent *) ev)->message_type
++        == spec->connect_request)
++    {
++        ReadXConnectMessage (ims, (XClientMessageEvent *) ev);
++        return True;
++    }
++    /*endif*/
++    return False;
++}
++
++static Bool WaitXIMProtocol (Display *dpy,
++                             Window win,
++                             XEvent *ev,
++                             XPointer client_data)
++{
++    extern void _Xi18nMessageHandler (XIMS, CARD16, unsigned char *, Bool *);
++    XIMS ims = (XIMS) client_data;
++    Xi18n i18n_core = ims->protocol;
++    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
++    Bool delete = True;
++    unsigned char *packet;
++    int connect_id;
++
++    if (((XClientMessageEvent *) ev)->message_type
++        == spec->xim_request)
++    {
++        if ((packet = ReadXIMMessage (ims,
++                                      (XClientMessageEvent *) ev,
++                                      &connect_id))
++            == (unsigned char *)  NULL)
++        {
++            return False;
++        }
++        /*endif*/
++        _Xi18nMessageHandler (ims, connect_id, packet, &delete);
++        if (delete == True)
++            XFree (packet);
++        /*endif*/
++        return True;
++    }
++    /*endif*/
++    return False;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/config.h b/src/plugins/platforminputcontexts/hime/include/config.h
+new file mode 100644
+index 0000000..2e9289e
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/config.h
+@@ -0,0 +1 @@
++#define GETTEXT_PACKAGE "hime"
+diff --git a/src/plugins/platforminputcontexts/hime/include/gst.h b/src/plugins/platforminputcontexts/hime/include/gst.h
+new file mode 100644
+index 0000000..3fecd34
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/gst.h
+@@ -0,0 +1,63 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef struct {
++  struct CHPHO *chpho;
++  int c_idx, c_len;
++  int ph_sta;  // phrase start
++  int sel_pho;
++//  int save_frm, save_to;
++  int current_page;
++  int startf;
++  gboolean full_match;
++  gboolean tsin_half_full;
++  gboolean tsin_buffer_editing;
++  gboolean ctrl_pre_sel;
++  struct PRE_SEL *pre_sel;
++  int pre_selN;
++  int last_cursor_idx;
++  int pho_menu_idx;
++//  int pho_sel_menu_idx;
++} TSIN_ST;
++extern TSIN_ST tss;
++
++typedef enum {
++  SAME_PHO_QUERY_none = 0,
++  SAME_PHO_QUERY_gtab_input = 1,
++  SAME_PHO_QUERY_pho_select = 2,
++} SAME_PHO_QUERY;
++
++typedef struct {
++  int ityp3_pho;
++  int cpg, maxi;
++  int start_idx, stop_idx;
++  char typ_pho[4];
++  char inph[8];
++  SAME_PHO_QUERY same_pho_query_state;
++} PHO_ST;
++extern PHO_ST poo;
++
++#define MAX_TAB_KEY_NUM64_6 (10)
++
++typedef struct {
++  int S1, E1, last_idx, wild_page, pg_idx, total_matchN, sel1st_i;
++  u_int64_t kval;
++  gboolean last_full, wild_mode, spc_pressed, invalid_spc, more_pg, gtab_buf_select;
++  short defselN, exa_match, ci, gbufN, gbuf_cursor;
++  KeySym inch[MAX_TAB_KEY_NUM64_6];
++} GTAB_ST;
++extern GTAB_ST ggg;
+diff --git a/src/plugins/platforminputcontexts/hime/include/gtab-buf.c b/src/plugins/platforminputcontexts/hime/include/gtab-buf.c
+new file mode 100644
+index 0000000..462931e
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/gtab-buf.c
+@@ -0,0 +1,1146 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "gtab.h"
++#include "hime-conf.h"
++#include "hime-endian.h"
++#include "pho.h"
++#include "tsin.h"
++#include "tsin-parse.h"
++#include "win-save-phrase.h"
++#include "gtab-buf.h"
++#include "gst.h"
++
++void disp_gbuf(), ClrIn(), clear_after_put();
++gboolean gtab_phrase_on();
++int page_len();
++void show_win_gtab();
++void disp_selection0(gboolean phrase_selected, gboolean force_disp);
++void disp_gtab_sel(char *s);
++void add_cache(int start, int usecount, TSIN_PARSE *out, short match_phr_N, short no_match_ch_N, int tc_len);
++int ch_pos_find(char *ch, int pos);
++void inc_gtab_usecount(char *str), ClrSelArea();
++void lookup_gtabn(char *ch, char *out);
++char *htmlspecialchars(char *s, char out[]);
++void hide_gtab_pre_sel();
++gboolean gtab_vertical_select_on();
++
++extern gboolean key_press_alt, key_press_ctrl;
++
++extern gboolean test_mode;
++
++GEDIT *gbuf;
++extern char **seltab;
++extern int ph_key_sz;
++
++void extract_gtab_key(int start, int len, void *out)
++{
++  int i;
++
++  char *p=(char *)out;
++  if (ph_key_sz==4) {
++    for(i=0; i < len; i++) {
++      u_int k = gbuf[i+start].keys[0];
++      memcpy(p, &k, sizeof(k));
++      p+=sizeof(k);
++    }
++  } else {
++    for(i=0; i < len; i++) {
++      memcpy(p, &gbuf[i+start].keys[0], sizeof(u_int64_t));
++      p+=sizeof(u_int64_t);
++    }
++  }
++}
++
++void extract_gbuf_str(int start, int len, char *out)
++{
++  int i;
++  out[0]=0;
++  for(i=0;i<len;i++)
++    strcat(out, gbuf[i+start].ch);
++}
++
++
++gboolean gtab_cursor_end()
++{
++  return ggg.gbuf_cursor==ggg.gbufN;
++}
++
++void dump_gbuf()
++{
++  int i;
++
++  for(i=0; i<ggg.gbufN; i++) {
++    int j;
++    for(j=0;j < gbuf[i].selN; j++)
++      printf("%d:%s ", j, gbuf[i].sel[j]);
++    puts("");
++  }
++}
++
++static unich_t latin_chars[]=
++"ÀÁÂÃÄÅÆÆÇÈÉÊËÌÍÎÏÐÐÑÒÓÔÕÖØÙÚÛÜÝÞÞßàáâãäåææçèéêëìíîïððñòóôõöøùúûüýþþÿ"
++"ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJIJijijĴĵĶķĸĹĺĻļĽľĿŀŁł"
++"ŃńŅņŇňʼnŊŋŌōŎŏŐőŒŒœœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž";
++
++int en_word_len(char *bf)
++{
++  char *s;
++
++  for(s=bf;*s;) {
++    int sz = utf8_sz(s);
++    if (sz==1) {
++      if (!((*s >= 'A' && *s<='Z') || (*s >= 'a' && *s<='z') || strchr("-_'", *s)))
++        break;
++    } else
++    if (sz==2) {
++      char *p;
++      for (p=latin_chars; *p; p+=2)
++        if (!memcmp(p, s, 2))
++          break;
++      if (!(*p))
++        break;
++    } else
++    if (sz>=3)
++      break;
++    s+=sz;
++  }
++
++  if (*s)
++    return 0;
++  return strlen(bf);
++}
++
++static char *gen_buf_str(int start, gboolean add_spc)
++{
++  int i;
++  char *out = tmalloc(char, 1);
++  int outN=0;
++
++  gboolean last_en_word = FALSE;
++  for(i=start;i<ggg.gbufN;i++) {
++    char *t = gbuf[i].ch;
++    int len = strlen(t);
++
++    if (add_spc && en_word_len(t) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
++      if (last_en_word) {
++        out = trealloc(out, char, outN+1);
++        out[outN++]=' ';
++      }
++      last_en_word = TRUE;
++    } else
++      last_en_word = FALSE;
++
++    out = trealloc(out, char, outN+len+1);
++    memcpy(out + outN, t, len);
++    outN+=len;
++  }
++
++  out[outN] = 0;
++  return out;
++}
++
++extern gboolean last_cursor_off;
++
++static char *gen_buf_str_disp()
++{
++  if (!ggg.gbufN) {
++    return strdup("");
++  }
++
++  int i;
++  char *out = tmalloc(char, 1);
++  int outN=0;
++
++  out[0]=0;
++  gbuf[ggg.gbufN].ch = " ";
++
++  gboolean last_is_en_word = FALSE;
++
++  int N = last_cursor_off ? ggg.gbufN-1:ggg.gbufN;
++  for(i=0;i<=N;i++) {
++    char addspc[MAX_CIN_PHR * 2 + 2];
++    char spec[MAX_CIN_PHR * 2 + 2];
++    int len = en_word_len(gbuf[i].ch);
++//    dbg("i %d N:%d bufN:%d\n",i,N,ggg.gbufN);
++    if (gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)
++      len = 0;
++//    dbg("%d %d is_en:%d\n",i, len, last_is_en_word);
++
++    if (len) {
++      if (last_is_en_word) {
++        strcpy(addspc, " ");
++        strcat(addspc, gbuf[i].ch);
++      } else
++        strcpy(addspc, gbuf[i].ch);
++      last_is_en_word = TRUE;
++    } else {
++      last_is_en_word = FALSE;
++      strcpy(addspc, gbuf[i].ch);
++    }
++
++    htmlspecialchars(addspc, spec);
++//    dbg("addspc '%s'  spec:%s out:%s\n", addspc, spec, out);
++
++    char www[MAX_CIN_PHR * 2 + 2];
++    char *t = spec;
++
++    if (i==ggg.gbuf_cursor) {
++      if (hime_win_color_use)
++        sprintf(www, "<span foreground=\"white\" background=\"%s\">%s</span>", tsin_cursor_color, spec);
++      else
++        sprintf(www, "<span foreground=\"white\" background=\""TSIN_CURSOR_COLOR_DEFAULT"\">%s</span>", spec);
++      t = www;
++    }
++
++    len = strlen(t);
++    out = trealloc(out, char, outN+len+1);
++    memcpy(out + outN, t, len);
++    outN+=len;
++    out[outN] = 0;
++  }
++
++  return out;
++}
++
++
++void disp_label_edit(char *str);
++
++static void free_pgbuf(GEDIT *p)
++{
++  int i;
++  for(i=0; i < p->selN; i++)
++    free(p->sel[i]);
++  free(p->sel);
++  p->ch = NULL;
++  p->sel=NULL;
++  p->flag = 0;
++}
++
++
++static void free_gbuf(int idx)
++{
++  free_pgbuf(&gbuf[idx]);
++}
++
++
++static void clear_gtab_buf_all()
++{
++  int i;
++  for(i=0;i<ggg.gbufN;i++)
++    free_gbuf(i);
++  ggg.gbuf_cursor = ggg.gbufN=0;
++  ggg.gtab_buf_select = 0;
++  disp_gbuf();
++}
++
++
++void disp_gbuf()
++{
++  char *bf=gen_buf_str_disp();
++  disp_label_edit(bf);
++
++  if (ggg.gbufN && gtab_disp_key_codes)
++    lookup_gtabn(gbuf[ggg.gbufN-1].ch, NULL);
++
++  free(bf);
++}
++
++void clear_gbuf_sel()
++{
++  ggg.gtab_buf_select = 0;
++  ggg.total_matchN = 0;
++  ClrSelArea();
++}
++
++int gbuf_cursor_left()
++{
++  hide_gtab_pre_sel();
++  if (!ggg.gbuf_cursor)
++    return ggg.gbufN;
++  if (ggg.gtab_buf_select)
++    clear_gbuf_sel();
++  ClrIn();
++  ggg.gbuf_cursor--;
++  disp_gbuf();
++  return 1;
++}
++
++
++int gbuf_cursor_right()
++{
++  hide_gtab_pre_sel();
++  if (ggg.gbuf_cursor==ggg.gbufN)
++    return ggg.gbufN;
++  if (ggg.gtab_buf_select)
++    clear_gbuf_sel();
++  ggg.gbuf_cursor++;
++  disp_gbuf();
++  return 1;
++}
++
++int gbuf_cursor_home()
++{
++  hide_gtab_pre_sel();
++  if (!ggg.gbufN)
++    return 0;
++  if (ggg.gtab_buf_select)
++    clear_gbuf_sel();
++
++  ggg.gbuf_cursor = 0;
++  disp_gbuf();
++  return 1;
++}
++
++
++int gbuf_cursor_end()
++{
++  hide_gtab_pre_sel();
++  if (!ggg.gbufN)
++    return 0;
++  if (ggg.gtab_buf_select)
++    clear_gbuf_sel();
++
++  ggg.gbuf_cursor = ggg.gbufN;
++  disp_gbuf();
++  return 1;
++}
++
++void inc_gtab_use_count(char *s);
++void inc_dec_tsin_use_count(void *pho, char *ch, int N);
++
++gboolean output_gbuf()
++{
++  hide_gtab_pre_sel();
++
++  if (!ggg.gbufN)
++    return FALSE;
++  char *bf=gen_buf_str(0, TRUE);
++#if 0
++  printf("out %s\n", bf);
++#endif
++
++#if 0
++  // single character
++  char *p;
++  for(p=bf; *p; p+=utf8_sz(p))
++    inc_gtab_use_count(p);
++#endif
++
++  send_text(bf);
++  free(bf);
++
++  int i;
++  for(i=0; i < ggg.gbufN;) {
++    char t[MAX_CIN_PHR+1];
++    t[0]=0;
++    inc_gtab_use_count(gbuf[i].ch);
++
++    int j;
++    for(j=i; j < i+gbuf[i].plen; j++)
++      strcat(t, gbuf[j].ch);
++
++    if (!gbuf[i].plen)
++      i++;
++    else {
++      u_int64_t kk[MAX_PHRASE_LEN];
++	  extract_gtab_key(i, gbuf[i].plen, kk);
++	  inc_dec_tsin_use_count(kk, t, gbuf[i].plen);
++      i+=gbuf[i].plen;
++    }
++  }
++
++
++  clear_gtab_buf_all();
++  ClrIn();
++  return TRUE;
++}
++
++
++gboolean check_gtab_fixed_mismatch(int idx, char *mtch, int plen)
++{
++  int j;
++  char *p = mtch;
++
++  for(j=0; j < plen; j++) {
++    int u8sz = utf8_sz(p);
++    if (!(gbuf[idx+j].flag & FLAG_CHPHO_FIXED))
++      continue;
++
++    if (memcmp(gbuf[idx+j].ch, p, u8sz))
++      break;
++
++    p+= u8sz;
++  }
++
++  if (j < plen)
++    return TRUE;
++
++  return FALSE;
++}
++
++void set_gtab_user_head()
++{
++  gbuf[ggg.gbuf_cursor].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
++}
++
++#define DBG 0
++
++void free_cache();
++void init_tsin_table();
++void set_tsin_parse_len(int);
++
++void gtab_parse()
++{
++  int i;
++  TSIN_PARSE out[MAX_PH_BF_EXT+1];
++  bzero(out, sizeof(out));
++
++  if (test_mode)
++    return;
++
++  if (ggg.gbufN <= 1)
++    return;
++
++  init_tsin_table();
++
++  init_cache(ggg.gbufN);
++
++  set_tsin_parse_len(ggg.gbufN);
++
++  short smatch_phr_N, sno_match_ch_N;
++  tsin_parse_recur(0, out, &smatch_phr_N, &sno_match_ch_N);
++#if 0
++  puts("vvvvvvvvvvvvvvvv");
++  for(i=0;  i < out[i].len; i++) {
++    printf("%x %d:", out[i].str, out[i].len);
++    utf8_putcharn(out[i].str, out[i].len);
++  }
++  dbg("\n");
++#endif
++
++  for(i=0; i < ggg.gbufN; i++)
++    gbuf[i].flag &= ~(FLAG_CHPHO_PHRASE_HEAD|FLAG_CHPHO_PHRASE_BODY);
++
++  int ofsi;
++  for(ofsi=i=0; out[i].len; i++) {
++    int j, ofsj;
++
++    if (out[i].flag & FLAG_TSIN_PARSE_PHRASE) {
++      gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_HEAD;
++      gbuf[ofsi].plen = out[i].len;
++    }
++
++    for(ofsj=j=0; j < out[i].len; j++) {
++      char *w = (char *)&out[i].str[ofsj];
++      int wsz = utf8_sz(w);
++      ofsj += wsz;
++
++      int k;
++      for(k=0;k<gbuf[ofsi].selN; k++) {
++        int sz = utf8_sz(gbuf[ofsi].sel[k]);
++        if (wsz == sz && !memcmp(gbuf[ofsi].sel[k], w, sz))
++          break;
++      }
++      if (k==gbuf[ofsi].selN) {
++#if 0
++        dbg("qq ");
++        utf8_putchar(w);
++        p_err(" err 1 selN:%d ofsi:%d", gbuf[ofsi].selN, ofsi);
++#endif
++        k=0;
++      }
++
++      if (!(gbuf[ofsi].flag & FLAG_CHPHO_FIXED)) {
++        gbuf[ofsi].ch = gbuf[ofsi].sel[k];
++        gbuf[ofsi].c_sel = k;
++      }
++      gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_BODY;
++
++      ofsi++;
++    }
++  }
++
++#if 0
++  puts("-----------------------------");
++  for(i=0;i<ggg.gbufN;i++)
++    puts(gbuf[i].ch);
++#endif
++  free_cache();
++}
++
++static GEDIT *cursor_gbuf()
++{
++  return ggg.gbuf_cursor == ggg.gbufN ? &gbuf[ggg.gbuf_cursor-1] : &gbuf[ggg.gbuf_cursor];
++}
++
++typedef struct {
++  char *s;
++  int usecount;
++  int org_seq;
++} GITEM;
++
++int get_gtab_use_count(char *s);
++
++int qcmp_gitem(const void *aa, const void *bb)
++{
++  int d = ((GITEM *)bb)->usecount - ((GITEM *)aa)->usecount;
++  if (d)
++    return d;
++
++  return ((GITEM *)aa)->org_seq - ((GITEM *)bb)->org_seq;
++}
++
++void hide_row2_if_necessary();
++
++unich_t auto_end_punch[] = ", . ? : ; ! [ ] 「 」 , 。 ? ; : 、 ~ ! ( )";
++GEDIT *insert_gbuf_cursor(char **sel, int selN, u_int64_t key, gboolean b_gtab_en_no_spc)
++{
++  hide_row2_if_necessary();
++
++  if (!sel || !selN)
++    return NULL;
++//  dbg("insert_gbuf_cursor %x\n", key);
++
++  gbuf=trealloc(gbuf, GEDIT, ggg.gbufN+2);
++
++  GEDIT *pbuf = &gbuf[ggg.gbuf_cursor];
++
++  if (ggg.gbuf_cursor < ggg.gbufN)
++    memmove(&gbuf[ggg.gbuf_cursor+1], &gbuf[ggg.gbuf_cursor], sizeof(GEDIT) * (ggg.gbufN - ggg.gbuf_cursor));
++
++  ggg.gbuf_cursor++;
++  ggg.gbufN++;
++
++  bzero(pbuf, sizeof(GEDIT));
++  bzero(gbuf+ggg.gbufN, sizeof(GEDIT));
++
++  GITEM *items = tmalloc(GITEM, selN);
++
++  int i;
++  for(i=0; i < selN; i++) {
++    items[i].s = sel[i];
++    items[i].org_seq = i;
++    items[i].usecount = get_gtab_use_count(sel[i]);
++  }
++  qsort(items, selN, sizeof(GITEM), qcmp_gitem);
++
++  for(i=0; i < selN; i++)
++    sel[i] = items[i].s;
++
++  pbuf->ch = sel[0];
++  pbuf->sel = sel;
++  pbuf->selN = selN;
++  pbuf->c_sel = 0;
++  pbuf->keys[0] = key;
++  pbuf->keysN=1;
++  pbuf->flag = b_gtab_en_no_spc ? FLAG_CHPHO_GTAB_BUF_EN_NO_SPC:0;
++
++  if (hime_punc_auto_send && ggg.gbufN==ggg.gbuf_cursor && selN==1 && strstr(_(auto_end_punch), sel[0])) {
++    char_play(pbuf->ch);
++    output_gbuf();
++  } else {
++    gtab_parse();
++    disp_gbuf();
++    char_play(pbuf->ch);
++  }
++
++  free(items);
++  return pbuf;
++}
++
++
++void set_gbuf_c_sel(int v)
++{
++  GEDIT *pbuf = cursor_gbuf();
++
++  pbuf->c_sel = v + ggg.pg_idx;
++  pbuf->ch = pbuf->sel[pbuf->c_sel];
++//  dbg("zzzsel v:%d %d %s\n",v, pbuf->c_sel,pbuf->ch);
++  pbuf->flag |= FLAG_CHPHO_FIXED;
++  ggg.gtab_buf_select = 0;
++  ggg.more_pg = 0;
++  disp_gtab_sel("");
++  gtab_parse();
++  disp_gbuf();
++//  dbg("zzzsel v:%d\n", pbuf->c_sel);
++}
++
++GEDIT *insert_gbuf_cursor1(char *s, u_int64_t key, gboolean b_gtab_en_no_spc)
++{
++   if (!gtab_phrase_on())
++     return NULL;
++
++//   dbg("insert_gbuf_cursor1 %s %x\n", s, key);
++   char **sel = tmalloc(char *, 1);
++   sel[0] = strdup(s);
++   GEDIT *e = insert_gbuf_cursor(sel, 1, key, b_gtab_en_no_spc);
++   clear_after_put();
++   return e;
++}
++
++void insert_gbuf_cursor_phrase(char *s, void *key, int N)
++{
++  u_int *key32 = (u_int *)key;
++  u_int64_t *key64 = (u_int64_t *)key;
++
++  int i;
++  for(i=0; i < N; i++) {
++    char ch[CH_SZ+1];
++    int n = utf8cpy(ch, s);
++    u_int64_t v = ph_key_sz==4?key32[i]:key64[i];
++    GEDIT *e = insert_gbuf_cursor1(ch, v, TRUE);
++    e->flag |= FLAG_CHPHO_FIXED;
++    s+=n;
++  }
++}
++
++static int key_N(u_int64_t k)
++{
++  int n=0;
++  int mask = (1 << KeyBits) - 1;
++
++  while (k) {
++    k>>=mask;
++    n++;
++  }
++
++  return n;
++}
++
++static int qcmp_key_N(const void *aa, const void *bb)
++{
++  u_int64_t a = *((u_int64_t *)aa);
++  u_int64_t b = *((u_int64_t *)bb);
++
++  return key_N(a) - key_N(b);
++}
++
++
++void insert_gbuf_nokey(char *s)
++{
++   if (!gtab_phrase_on())
++     return;
++
++//   dbg("insert_gbuf_nokey\n");
++
++   int i;
++   u_int64_t keys[32];
++   int keysN=0;
++   int sz = utf8_sz(s);
++
++   keys[0]=0;
++   if (cur_inmd->tbl64) {
++     for(i=0; i < cur_inmd->DefChars; i++) {
++       if (!memcmp(cur_inmd->tbl64[i].ch, s, sz)) {
++         u_int64_t t;
++         memcpy(&t, cur_inmd->tbl64[i].key, sizeof(u_int64_t));
++         keys[keysN++] = t;
++       }
++     }
++   } else
++   if (cur_inmd->tbl) {
++     for(i=0; i < cur_inmd->DefChars; i++) {
++       if (!memcmp(cur_inmd->tbl[i].ch, s, sz)) {
++         u_int t;
++         memcpy(&t, cur_inmd->tbl[i].key, sizeof(u_int));
++         keys[keysN++] = t;
++       }
++     }
++   }
++
++   qsort(keys, keysN, sizeof(u_int64_t), qcmp_key_N);
++
++   GEDIT *e = insert_gbuf_cursor1(s, keys[0], TRUE);
++   if (keysN > 8)
++     keysN = 8;
++
++   memcpy(e->keys, keys, sizeof(u_int64_t) * keysN);
++   e->keysN = keysN;
++}
++
++void insert_gbuf_cursor1_cond(char *s, u_int64_t key, gboolean valid_key)
++{
++  if (valid_key)
++    insert_gbuf_cursor1(s, key, FALSE);
++  else
++    insert_gbuf_nokey(s);
++}
++
++void insert_gbuf_cursor_char(char ch)
++{
++  char t[2];
++  t[0]=ch;
++  t[1]=0;
++  insert_gbuf_cursor1(t, 0, TRUE);
++}
++
++gboolean gtab_has_input();
++void hide_win_gtab();
++
++int gtab_buf_delete_ex(gboolean auto_hide)
++{
++  if (ggg.gbuf_cursor==ggg.gbufN)
++    return 0;
++
++  if (test_mode)
++    return 1;
++
++  if (ggg.gtab_buf_select)
++    clear_gbuf_sel();
++
++  free_gbuf(ggg.gbuf_cursor);
++  memmove(&gbuf[ggg.gbuf_cursor], &gbuf[ggg.gbuf_cursor+1], sizeof(GEDIT) * (ggg.gbufN - ggg.gbuf_cursor -1));
++  ggg.gbufN--;
++  disp_gbuf();
++
++  if (hime_pop_up_win && !gtab_has_input() && auto_hide)
++    hide_win_gtab();
++
++  return 1;
++}
++
++int gtab_buf_delete()
++{
++  return gtab_buf_delete_ex(TRUE);
++}
++
++
++gboolean gtab_has_input();
++void hide_win_gtab();
++
++int gtab_buf_backspace_ex(gboolean auto_hide)
++{
++  if (!ggg.gbuf_cursor) {
++    return ggg.gbufN>0;
++  }
++  ggg.gbuf_cursor--;
++  gtab_buf_delete_ex(auto_hide);
++
++  if (hime_pop_up_win && !gtab_has_input() && auto_hide)
++    hide_win_gtab();
++
++  return 1;
++}
++
++int gtab_buf_backspace()
++{
++  return gtab_buf_backspace_ex(TRUE);
++}
++
++
++void gtab_buf_backspaceN(int n)
++{
++  int i;
++  for(i=0; i < n; i++)
++    gtab_buf_backspace_ex(FALSE);
++}
++
++extern int more_pg;
++
++void gtab_disp_sel()
++{
++  int idx = ggg.gbuf_cursor==ggg.gbufN ? ggg.gbuf_cursor-1:ggg.gbuf_cursor;
++  GEDIT *pbuf=&gbuf[idx];
++
++  int i;
++  for(i=0; i < cur_inmd->M_DUP_SEL; i++) {
++    int v = i + ggg.pg_idx;
++    if (v >= pbuf->selN)
++      seltab[i][0]=0;
++    else
++      strcpy(seltab[i], pbuf->sel[v]);
++  }
++
++  if (pbuf->selN > page_len())
++    ggg.more_pg = 1;
++  disp_selection0(FALSE, TRUE);
++  show_win_gtab();
++}
++
++
++int show_buf_select()
++{
++  if (!ggg.gbufN)
++    return 0;
++
++  int idx = ggg.gbuf_cursor==ggg.gbufN ? ggg.gbuf_cursor-1:ggg.gbuf_cursor;
++  GEDIT *pbuf=&gbuf[idx];
++  ggg.gtab_buf_select = 1;
++  ggg.total_matchN = pbuf->selN;
++  ggg.pg_idx = 0;
++
++  gtab_disp_sel();
++  hide_gtab_pre_sel();
++
++  return 1;
++}
++
++void gbuf_prev_pg()
++{
++  ggg.pg_idx -= page_len();
++  if (ggg.pg_idx < 0)
++    ggg.pg_idx = 0;
++
++  gtab_disp_sel();
++}
++
++void gbuf_next_pg()
++{
++  ggg.pg_idx += page_len();
++  if (ggg.pg_idx >= ggg.total_matchN)
++    ggg.pg_idx = 0;
++
++  gtab_disp_sel();
++}
++
++#include "im-client/hime-im-client-attr.h"
++
++int get_DispInArea_str(char *out);
++
++int gtab_get_preedit(char *str, HIME_PREEDIT_ATTR attr[], int *pcursor, int *sub_comp_len)
++{
++  int i=0;
++  int strN=0;
++  int attrN=0;
++  int ch_N=0;
++
++//  dbg("gtab_get_preedit\n");
++  str[0]=0;
++  *pcursor=0;
++
++  *sub_comp_len = ggg.ci > 0;
++#if 1
++  if (ggg.gbufN && !hime_edit_display_ap_only())
++	*sub_comp_len|=4;
++#endif
++  gboolean ap_only = hime_edit_display_ap_only();
++
++  if (gtab_phrase_on()) {
++    attr[0].flag=HIME_PREEDIT_ATTR_FLAG_UNDERLINE;
++    attr[0].ofs0=0;
++
++    if (ggg.gbufN)
++      attrN=1;
++
++    gboolean last_is_en_word = FALSE;
++    for(i=0; i < ggg.gbufN; i++) {
++      char *s = gbuf[i].ch;
++      char tt[MAX_CIN_PHR+2];
++
++      if (en_word_len(s) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
++        if (last_is_en_word) {
++          strcpy(tt, " ");
++          strcat(tt, s);
++          s = tt;
++        }
++        last_is_en_word = TRUE;
++      } else {
++        last_is_en_word = FALSE;
++      }
++
++      int len = strlen(s);
++      int N = utf8_str_N(s);
++      ch_N+=N;
++      if (i < ggg.gbuf_cursor)
++        *pcursor+=N;
++      if (ap_only && i==ggg.gbuf_cursor) {
++        attr[1].ofs0=*pcursor;
++        attr[1].ofs1=*pcursor+N;
++        attr[1].flag=HIME_PREEDIT_ATTR_FLAG_REVERSE;
++        attrN++;
++      }
++
++      if (hime_display_on_the_spot_key() && i==ggg.gbuf_cursor)
++        strN += get_DispInArea_str(str+strN);
++
++      memcpy(str+strN, s, len);
++      strN+=len;
++    }
++  }
++
++
++  if (hime_display_on_the_spot_key() && i==ggg.gbuf_cursor)
++    strN += get_DispInArea_str(str+strN);
++
++  str[strN]=0;
++
++  attr[0].ofs1 = ch_N;
++  return attrN;
++}
++
++extern GtkWidget *gwin_gtab;
++void gtab_reset()
++{
++  if (!gwin_gtab)
++    return;
++  clear_gtab_buf_all();
++  clear_gbuf_sel();
++  ClrIn();
++  return;
++}
++
++int ch_to_gtab_keys(INMD *tinmd, char *ch, u_int64_t keys[]);
++
++void save_gtab_buf_phrase_idx(int idx0, int len)
++{
++  WSP_S wsp[MAX_PHRASE_LEN];
++
++  bzero(wsp, sizeof(wsp));
++  int i;
++  for(i=0; i < len; i++) {
++    u8cpy(wsp[i].ch, gbuf[idx0 + i].ch);
++    u_int64_t key = gbuf[idx0 + i].keys[0];
++
++    if (!key) {
++      u_int64_t keys[64];
++      int keysN = ch_to_gtab_keys(cur_inmd, wsp[i].ch, keys);
++      if (keysN)
++        key = keys[0];
++    }
++
++    wsp[i].key = key;
++  }
++
++  create_win_save_phrase(wsp, len);
++}
++
++void save_gtab_buf_phrase(KeySym key)
++{
++  int len = key - '0';
++  int idx0 = ggg.gbuf_cursor - len;
++  int idx1 = ggg.gbuf_cursor - 1;
++
++  if (idx0 < 0 || idx0 > idx1)
++    return;
++
++  save_gtab_buf_phrase_idx(idx0, len);
++}
++
++gboolean save_gtab_buf_shift_enter()
++{
++  if (!ggg.gbufN)
++    return 0;
++  int idx0 = 0;
++  if (ggg.gbufN != ggg.gbuf_cursor)
++    idx0 = ggg.gbuf_cursor;
++  int len = ggg.gbufN - idx0;
++  if (len > MAX_PHRASE_LEN)
++    return 0;
++
++  save_gtab_buf_phrase_idx(idx0, len);
++  gbuf_cursor_end();
++  return 1;
++}
++
++
++void load_tsin_db0(char *infname, gboolean is_gtab_i);
++gboolean init_tsin_table_fname(INMD *p, char *fname);
++
++void init_tsin_table()
++{
++  char fname[256];
++  if (!current_CS)
++    return;
++
++  init_tsin_table_fname(&inmd[current_CS->in_method], fname);
++  load_tsin_db0(fname, TRUE);
++}
++
++extern u_char scanphr_e(int chpho_idx, int plen, gboolean pho_incr, int *rselN);
++void init_pre_sel();
++void clear_sele();
++void set_sele_text(int tN, int i, char *text, int len);
++void get_win_gtab_geom();
++void disp_selections(int x, int y);
++
++gboolean use_tsin_sel_win();
++void init_tsin_selection_win();
++
++static int gtab_pre_select_phrase_len;
++
++void disp_gtab_pre_sel(char *s);
++extern GtkWidget *gwin1;
++
++void gtab_scan_pre_select(gboolean b_incr)
++{
++  if (!gtab_phrase_pre_select)
++    return;
++//  dbg("gtab_scan_pre_select\n");
++
++  tss.pre_selN = 0;
++
++  hide_gtab_pre_sel();
++
++  if (!gtab_cursor_end() || !ggg.gbufN)
++    return;
++
++  init_tsin_table();
++  init_pre_sel();
++
++  int Maxlen = ggg.gbufN;
++  if (Maxlen > MAX_PHRASE_LEN)
++    Maxlen = MAX_PHRASE_LEN;
++
++  int len, selN, max_len=-1, max_selN;
++  for(len=1; len <= Maxlen; len++) {
++    int idx = ggg.gbufN - len;
++    if (gbuf[idx].flag & FLAG_CHPHO_PHRASE_TAIL)
++      break;
++    int mlen = scanphr_e(ggg.gbufN - len, len, b_incr, &selN);
++    if (mlen) {
++      max_len = len;
++      max_selN = selN;
++    }
++  }
++
++//  dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
++
++  if (max_len < 0 || max_selN >= strlen(cur_inmd->selkey) * 2) {
++    tss.pre_selN = 0;
++    return;
++  }
++
++  gtab_pre_select_phrase_len = max_len;
++
++  scanphr_e(ggg.gbufN - max_len, max_len, b_incr, &selN);
++
++//  dbg("selN:%d %d\n", selN, tss.pre_selN);
++
++  if (selN==1 && tss.pre_sel[0].len==max_len) {
++    char out[MAX_PHRASE_LEN * CH_SZ + 1];
++    extract_gbuf_str(ggg.gbufN - max_len, max_len, out);
++    if (!strcmp(out, tss.pre_sel[0].str))
++      return;
++  }
++
++//  dbg("selN %d %d\n",selN, tss.pre_selN);
++
++  if (use_tsin_sel_win()) {
++	if (gwin1)
++      clear_sele();
++	else
++      init_tsin_selection_win();
++
++    int i;
++    for(i=0;i<tss.pre_selN; i++)
++       set_sele_text(tss.pre_selN,i,tss.pre_sel[i].str, -1);
++    get_win_gtab_geom();
++    disp_selections(-1, -1);
++    return;
++  }
++
++  char tt[4096];
++  tt[0]=0;
++  int i;
++
++  for(i=0;i<tss.pre_selN; i++) {
++    char ts[(MAX_PHRASE_LEN+3) * CH_SZ + 1];
++    char *br= (i < tss.pre_selN-1 && gtab_vertical_select_on())?"\n":"";
++    if (hime_win_color_use)
++      sprintf(ts, "<span foreground=\"%s\">%c</span>%s%s", hime_sel_key_color, cur_inmd->selkey[i], tss.pre_sel[i].str, br);
++    else
++      sprintf(ts, "<span foreground=\""HIME_SEL_KEY_COLOR_DEFAULT"\">%c</span>%s%s", cur_inmd->selkey[i], tss.pre_sel[i].str, br);
++    strcat(tt, ts);
++    if (!gtab_vertical_select_on() && i < tss.pre_selN-1)
++      strcat(tt, " ");
++  }
++
++//  dbg("tt %s\n", tt);
++  disp_gtab_pre_sel(tt);
++}
++
++
++int shift_key_idx(char *s, KeySym xkey);
++
++gboolean gtab_pre_select_idx(int c)
++{
++  if (c < 0)
++    return FALSE;
++  if (c >= tss.pre_selN)
++    return TRUE;
++
++#if 0
++  dbg("c %d %s  ggg.gbuf_cursor:%d,%d\n", c, tss.pre_sel[c].str,
++    ggg.gbuf_cursor, ggg.gbufN);
++#endif
++
++  gtab_buf_backspaceN(gtab_pre_select_phrase_len);
++  int len = tss.pre_sel[c].len;
++  insert_gbuf_cursor_phrase(tss.pre_sel[c].str, tss.pre_sel[c].phkey, len);
++  gbuf[ggg.gbufN-1].flag |= FLAG_CHPHO_PHRASE_TAIL;
++
++  hide_gtab_pre_sel();
++  if (hime_pop_up_win)
++    hide_win_gtab();
++
++  return TRUE;
++}
++
++gboolean gtab_pre_select_shift(KeySym key, int kbstate)
++{
++//  dbg("gtab_pre_select_shift %c\n", key);
++  if (!gtab_phrase_pre_select || !tss.pre_selN)
++    return FALSE;
++
++  int c = shift_key_idx(cur_inmd->selkey, key);
++  return gtab_pre_select_idx(c);
++}
++
++void tsin_toggle_eng_ch();
++
++int feedkey_gtab_release(KeySym xkey, int kbstate)
++{
++  switch (xkey) {
++     case XK_Control_L:
++     case XK_Control_R:
++       if (key_press_ctrl && tss.pre_selN) {
++         if (!test_mode) {
++           tss.ctrl_pre_sel = TRUE;
++         }
++	 key_press_ctrl = FALSE;
++         return 1;
++       } else
++         return 0;
++#if 1
++     case XK_Shift_L:
++     case XK_Shift_R:
++// dbg("release xkey %x\n", xkey);
++        if (((tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Shift) ||
++             (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftL && xkey == XK_Shift_L) ||
++             (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftR && xkey == XK_Shift_R)) &&
++	     key_press_alt) {
++          if (!test_mode) {
++            tsin_toggle_eng_ch();
++          }
++	  key_press_alt = FALSE;
++          return 1;
++        } else
++          return 0;
++#endif
++     default:
++        return 0;
++  }
++}
++
++#include "win1.h"
++
++void gtab_set_win1_cb()
++{
++  set_win1_cb((cb_selec_by_idx_t)gtab_pre_select_idx, NULL, NULL);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/gtab-buf.h b/src/plugins/platforminputcontexts/hime/include/gtab-buf.h
+new file mode 100644
+index 0000000..6ee7803
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/gtab-buf.h
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef struct {
++  char *ch;
++  char **sel;
++  int selN;
++  u_short flag;
++  u_char c_sel;
++  char plen, keysN;
++  u_int64_t keys[8];
++} GEDIT;
++
++extern GEDIT *gbuf;
++extern short gbufN;
++
++void insert_gbuf_nokey(char *s);
++void insert_gbuf_cursor1_cond(char *s, u_int64_t key, gboolean valid_key);
++GEDIT *insert_gbuf_cursor(char **sel, int selN, u_int64_t key, gboolean b_gtab_en_no_spc);
+diff --git a/src/plugins/platforminputcontexts/hime/include/gtab.c b/src/plugins/platforminputcontexts/hime/include/gtab.c
+new file mode 100644
+index 0000000..708fa06
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/gtab.c
+@@ -0,0 +1,1832 @@
++/* Copyright (C) 2004-2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <sys/stat.h>
++#include <regex.h>
++#include "hime.h"
++#include "gtab.h"
++#include "pho.h"
++#include "hime-conf.h"
++#include "hime-endian.h"
++#include "gtab-buf.h"
++#include "tsin.h"
++#include "gst.h"
++
++extern gboolean test_mode;
++gboolean gtab_phrase_on();
++gboolean gtab_disp_partial_match_on(), gtab_vertical_select_on(), gtab_pre_select_on(), gtab_unique_auto_send_on(), gtab_press_full_auto_send_on();
++void init_seltab(char ***p);
++
++extern gboolean key_press_alt, key_press_ctrl;
++
++extern GtkWidget *gwin_gtab;
++void hide_gtab_pre_sel();
++void gtab_scan_pre_select(gboolean);
++
++extern GTAB_space_pressed_E _gtab_space_auto_first;
++extern char *TableDir;
++
++extern INMD *cur_inmd;
++extern char **seltab;
++
++extern char str_key_codes[128];
++void disp_pho_sel(char *s);
++
++#define gtab_full_space_auto_first (_gtab_space_auto_first & (GTAB_space_auto_first_any|GTAB_space_auto_first_full))
++#define AUTO_SELECT_BY_PHRASE (gtab_phrase_on())
++
++gboolean use_tsin_sel_win()
++{
++  return  gtab_vertical_select_on() && gtab_phrase_pre_select;
++}
++
++
++static gboolean gtab_pre_select_or_partial_on()
++{
++  return gtab_pre_select_on() || (cur_inmd->flag&FLAG_GTAB_DISP_PARTIAL_MATCH)!=0;
++}
++
++gboolean same_query_show_pho_win()
++{
++  return poo.same_pho_query_state != SAME_PHO_QUERY_none;
++}
++
++gboolean hime_edit_display_ap_only();
++gboolean gtab_has_input()
++{
++  int i;
++
++  for(i=0; i < MAX_TAB_KEY_NUM64_6; i++)
++    if (ggg.inch[i])
++      return TRUE;
++
++  if (same_query_show_pho_win())
++    return TRUE;
++
++  if (ggg.gtab_buf_select)
++    return TRUE;
++
++  if (ggg.gbufN && !hime_edit_display_ap_only())
++    return TRUE;
++
++  return FALSE;
++}
++
++#define tblch(i) tblch2(cur_inmd, i)
++
++int load_phr_ch(INMD *inm, u_char *ch, char *tt)
++{
++  int phrno =((int)(ch[0])<<16)|((int)ch[1]<<8)|ch[2];
++  int ofs = inm->phridx[phrno], ofs1 = inm->phridx[phrno+1];
++
++//  dbg("load_phr   j:%d %d %d %d\n", j, phrno, ofs, ofs1);
++  int len = ofs1 - ofs;
++
++  if (len > MAX_CIN_PHR || len <= 0) {
++    dbg("phrae error %d\n", len);
++    strcpy(tt,"err");
++    return 0;
++  }
++
++  memcpy(tt, inm->phrbuf + ofs, len);
++  tt[len]=0;
++  return len;
++}
++
++static void load_phr(int j, char *tt)
++{
++  u_char *ch = tblch(j);
++
++  load_phr_ch(cur_inmd, ch, tt);
++}
++
++static int qcmp_strlen(const void *aa, const void *bb)
++{
++  char *a = *((char **)aa), *b = *((char **)bb);
++
++  return strlen(a) - strlen(b);
++}
++
++void set_key_codes_label(char *s, int better);
++void set_page_label(char *s);
++
++static void clear_page_label()
++{
++  set_page_label("");
++}
++
++int gtab_key2name(INMD *tinmd, u_int64_t key, char *t, int *rtlen);
++
++
++int ch_to_gtab_keys(INMD *tinmd, char *ch, u_int64_t keys[])
++{
++  int n = utf8_str_N(ch);
++  gboolean phrase = n > 1 || !(ch[0] & 0x80);
++  int i, keysN=0;
++  for(i=0; i < tinmd->DefChars; i++) {
++    char *chi = (char *)tblch2(tinmd, i);
++
++    if (phrase) {
++      if ((chi[0] & 0x80))
++        continue;
++      char tstr[512];
++      load_phr_ch(tinmd, (u_char *)chi, tstr);
++      if (strcmp(tstr, ch))
++        continue;
++    } else {
++      if (!(chi[0] & 0x80))
++        continue;
++      if (!utf8_eq(chi, ch))
++        continue;
++    }
++
++    u_int64_t key = CONVT2(tinmd, i);
++    keys[keysN++] = key;
++  }
++  return keysN;
++}
++
++void lookup_gtabn(char *ch, char *out)
++{
++  char outbuf[512];
++  char *tbuf[128];
++  int tbufN=0;
++  INMD *tinmd = &inmd[default_input_method];
++
++  if (!tinmd->DefChars)
++    tinmd = cur_inmd;
++
++  if (!tinmd)
++    return;
++
++  gboolean need_disp = FALSE;
++
++  if (!out) {
++    out = outbuf;
++    need_disp = TRUE;
++  }
++
++  out[0]=0;
++
++
++  int min_klen = 100;
++  u_int64_t keys[64];
++  int keysN = ch_to_gtab_keys(tinmd, ch, keys);
++
++  int i;
++  for(i=0; i < keysN; i++) {
++    int tlen, klen;
++    char t[CH_SZ * 10 + 1];
++
++    klen = gtab_key2name(tinmd, keys[i], t, &tlen);
++
++    if (klen < min_klen)
++      min_klen = klen;
++
++    t[tlen]=0;
++
++    tbuf[tbufN] = strdup(t);
++    tbufN++;
++  }
++
++
++  qsort(tbuf, tbufN, sizeof(char *), qcmp_strlen);
++  out[0]=0;
++
++  for(i=0; i < tbufN; i++) {
++#define MAX_DISP_MATCH 40
++    if (strlen(out) < MAX_DISP_MATCH) {
++      strcat(out, tbuf[i]);
++      if (i < tbufN-1)
++        strcat(out, " |");
++    }
++
++    free(tbuf[i]);
++  }
++
++  if (!out[0] || !need_disp)
++    return;
++
++
++  set_key_codes_label(out, ggg.ci > min_klen);
++  void set_key_codes_label_pho(char *s);
++  set_key_codes_label_pho(out);
++}
++
++void lookup_gtab(char *ch)
++{
++  char tt[CH_SZ+1];
++  utf8cpy(tt, ch);
++  lookup_gtabn(tt, NULL);
++}
++
++
++void lookup_gtab_out(char *ch, char *out)
++{
++  char tt[CH_SZ+1];
++  utf8cpy(tt, ch);
++  lookup_gtabn(tt, out);
++}
++
++void free_gtab()
++{
++  int i;
++
++  for(i=0; i < inmdN; i++) {
++    INMD *inp = &inmd[i];
++    free(inp->tbl); inp->tbl = NULL;
++    free(inp->tbl64); inp->tbl64 = NULL;
++    free(inp->phridx); inp->phridx = NULL;
++    free(inp->phrbuf); inp->phrbuf = NULL;
++    free(inp->keyname_lookup); inp->keyname_lookup = NULL;
++  }
++
++  free(inmd);
++}
++
++
++char *b1_cat(char *s, char c)
++{
++  char t[2];
++  t[0]=c;
++  t[1]=0;
++
++  return strcat(s, t);
++}
++
++
++char *bch_cat(char *s, char *ch)
++{
++  char t[CH_SZ + 1];
++  int len = u8cpy(t, ch);
++  t[len]=0;
++
++  return strcat(s, t);
++}
++
++
++void disp_gtab_sel(char *s);
++
++void ClrSelArea()
++{
++  disp_gtab_sel("");
++//  hide_gtab_pre_sel();
++}
++
++
++void disp_gtab(char *);
++void clear_gtab_input_error_color();
++
++static void clr_seltab()
++{
++  int i;
++  if (!seltab)
++    return;
++
++  for(i=0; i < MAX_SELKEY; i++)
++     seltab[i][0]=0;
++}
++
++void clear_gtab_in_area(), hide_win_gtab();
++void ClrIn()
++{
++  bzero(ggg.inch,sizeof(ggg.inch));
++  clr_seltab();
++  ggg.total_matchN=ggg.pg_idx=ggg.more_pg=ggg.wild_mode=ggg.wild_page=ggg.last_idx=ggg.defselN=ggg.exa_match=
++  ggg.spc_pressed=ggg.ci=ggg.invalid_spc=0;
++
++  ggg.sel1st_i=MAX_SELKEY-1;
++
++  clear_gtab_in_area();
++  ggg.last_idx = 0;
++
++  if (hime_pop_up_win && !gtab_has_input() && !tss.pre_selN)
++    hide_win_gtab();
++
++  clear_gtab_input_error_color();
++  clear_page_label();
++//  hide_gtab_pre_sel();
++}
++
++
++void hide_win_pho();
++
++void close_gtab_pho_win()
++{
++  if (test_mode)
++    return;
++  if (same_query_show_pho_win()) {
++    poo.same_pho_query_state = SAME_PHO_QUERY_none;
++    hide_win_pho();
++    if (hime_pop_up_win && (str_key_codes[0]!='\0'))
++      hide_win_gtab();
++  }
++}
++
++void gtab_disp_empty(char *tt, int N);
++extern int win_gtab_max_key_press;
++
++static void DispInArea()
++{
++  int i;
++
++//  hide_gtab_pre_sel();
++
++//  dbg("sel1st:%d\n", ggg.sel1st_i);
++  if (hime_display_on_the_spot_key()) {
++    if (hime_pop_up_win && gwin_gtab && GTK_WIDGET_VISIBLE(gwin_gtab) && poo.same_pho_query_state == SAME_PHO_QUERY_none)
++      hide_win_gtab();
++    return;
++  }
++
++  char tt[128];
++  int ttN=0;
++
++  if (win_gtab_max_key_press < ggg.ci)
++    win_gtab_max_key_press = ggg.ci;
++
++  for(i=0;i<ggg.ci;i++) {
++    char *p=(char *)&cur_inmd->keyname[ggg.inch[i] * CH_SZ];
++    int len;
++    if (*p & 0x80)
++      len=utf8cpy(tt+ttN, p);
++    else {
++      len = strlen(p);
++      strcpy(tt+ttN, p);
++    }
++
++    ttN+=len;
++  }
++
++  tt[ttN]=0;
++
++  gtab_disp_empty(tt, win_gtab_max_key_press - i);
++
++  disp_gtab(tt);
++}
++
++int get_DispInArea_str(char *out)
++{
++  int outN=0, i;
++  for(i=0;i<ggg.ci;i++) {
++    char *p = (char *)&cur_inmd->keyname[ggg.inch[i] * CH_SZ];
++    if (*p & 0x80)
++      outN+=u8cpy(out+outN, p);
++    else {
++      int len = strlen(p);
++      memcpy(out+outN, p, len);
++      outN+=len;
++    }
++  }
++
++#if 0
++  if (outN) {
++    hide_gtab_pre_sel();
++  }
++#endif
++
++  out[outN]=0;
++//  dbg("get_DispInArea_str\n", out);
++  return outN;
++}
++
++
++void set_gtab_input_method_name(char *s);
++void case_inverse(KeySym *xkey, int shift_m);
++
++extern unich_t *fullchar[];
++
++void start_gtab_pho_query(char *utf8);
++
++void clear_after_put()
++{
++  ClrIn();
++  ClrSelArea();
++}
++
++void add_to_tsin_buf_str(char *str);
++gboolean init_in_method(int in_no);
++void hide_win_kbm();
++
++void hide_row2_if_necessary()
++{
++  if ((!ggg.wild_mode && gtab_hide_row2) || !gtab_disp_key_codes) {
++    set_key_codes_label(NULL, 0);
++  }
++}
++
++static void putstr_inp(char *p)
++{
++  clear_page_label();
++
++//  dbg("gtab_hide_row2 %d\n", gtab_hide_row2);
++  hide_row2_if_necessary();
++
++  char_play(p);
++
++  int to_tsin = (cur_inmd->flag & FLAG_GTAB_SYM_KBM) && inmd[default_input_method].method_type==method_type_TSIN && tss.c_len;
++
++  if (utf8_str_N(p) > 1  || !(p[0]&128)) {
++    if ((gtab_disp_key_codes && !gtab_hide_row2) || ggg.wild_mode)
++      lookup_gtabn(p, NULL);
++    if (to_tsin) {
++      add_to_tsin_buf_str(p);
++    }
++    else
++      send_text(p);
++  }
++  else {
++    if (poo.same_pho_query_state == SAME_PHO_QUERY_gtab_input) {
++      poo.same_pho_query_state = SAME_PHO_QUERY_pho_select;
++      start_gtab_pho_query(p);
++
++      ClrIn();
++      ClrSelArea();
++      return;
++    }
++
++    if ((gtab_disp_key_codes && !gtab_hide_row2) || ggg.wild_mode)
++      lookup_gtab(p);
++
++    if (to_tsin)
++      add_to_tsin_buf_str(p);
++    else
++      send_utf8_ch(p);
++  }
++
++  clear_after_put();
++
++  if ((cur_inmd->flag & FLAG_GTAB_SYM_KBM)) {
++    extern int win_kbm_inited, hime_show_win_kbm;
++    init_in_method(default_input_method);
++    if (win_kbm_inited && !hime_show_win_kbm)
++      hide_win_kbm();
++  }
++}
++
++
++#define swap(a,b) { tt=a; a=b; b=tt; }
++
++static u_int vmask[]=
++{ 0,
++ (0x3f<<24),
++ (0x3f<<24)|(0x3f<<18),
++ (0x3f<<24)|(0x3f<<18)|(0x3f<<12),
++ (0x3f<<24)|(0x3f<<18)|(0x3f<<12)|(0x3f<<6),
++ (0x3f<<24)|(0x3f<<18)|(0x3f<<12)|(0x3f<<6)|0x3f
++};
++
++
++static u_int vmask_7[]=
++{ 0,
++ (0x7f<<21),
++ (0x7f<<21)|(0x7f<<14),
++ (0x7f<<21)|(0x7f<<14)|(0x7f<<7),
++ (0x7f<<21)|(0x7f<<14)|(0x7f<<7)|0x7f,
++};
++
++#define KKK ((u_int64_t)0x3f)
++
++
++static u_int64_t vmask64[]=
++{ 0,
++  (KKK<<54),
++  (KKK<<54)|(KKK<<48),
++  (KKK<<54)|(KKK<<48)|(KKK<<42),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30)|(KKK<<24),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30)|(KKK<<24)|(KKK<<18),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30)|(KKK<<24)|(KKK<<18)|(KKK<<12),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30)|(KKK<<24)|(KKK<<18)|(KKK<<12)|(KKK<<6),
++  (KKK<<54)|(KKK<<48)|(KKK<<42)|(KKK<<36)|(KKK<<30)|(KKK<<24)|(KKK<<18)|(KKK<<12)|(KKK<<6)|KKK
++};
++
++
++#define KKK7 ((u_int64_t)0x7f)
++
++static u_int64_t vmask64_7[]=
++{ 0,
++ (KKK7<<56),
++ (KKK7<<56)|(KKK7<<49),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35)|(KKK7<<28),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35)|(KKK7<<28)|(KKK7<<21),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35)|(KKK7<<28)|(KKK7<<21)|(KKK7<<14),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35)|(KKK7<<28)|(KKK7<<21)|(KKK7<<14)|(KKK7<<7),
++ (KKK7<<56)|(KKK7<<49)|(KKK7<<42)|(KKK7<<35)|(KKK7<<28)|(KKK7<<21)|(KKK7<<14)|(KKK7<<7)|KKK7,
++};
++
++
++#define KEY_N (cur_inmd->max_keyN)
++
++static gboolean load_seltab(int tblidx, int seltabidx)
++{
++  u_char *tbl_ch = tblch(tblidx);
++  if (tbl_ch[0] < 0x80) {
++    load_phr(tblidx, seltab[seltabidx]);
++    return TRUE;
++  }
++
++  int len = u8cpy(seltab[seltabidx], (char *)tbl_ch);
++  seltab[seltabidx][len] = 0;
++
++  return FALSE;
++}
++
++
++static char* load_tblidx(int tblidx)
++{
++  char tt[MAX_CIN_PHR];
++  u_char *tbl_ch = tblch(tblidx);
++  if (tbl_ch[0] < 0x80) {
++    load_phr(tblidx, tt);
++  } else {
++    int len = u8cpy(tt, (char *)tbl_ch);
++    tt[len] = 0;
++  }
++
++  return strdup(tt);
++}
++
++
++void set_gtab_input_error_color();
++static void bell_err()
++{
++  if (test_mode)
++    return;
++
++  bell();
++  set_gtab_input_error_color();
++}
++
++gboolean cmp_inmd_idx(regex_t *reg, int idx)
++{
++  u_int64_t kk=CONVT2(cur_inmd, idx);
++  char ts[32];
++  int tsN=0;
++
++  ts[tsN++]= ' ';
++
++  int i;
++  for(i=0; i < KEY_N; i++) {
++    char c = (kk >> (LAST_K_bitN - i*cur_inmd->keybits)) & cur_inmd->kmask;
++    if (!c)
++      break;
++    ts[tsN++] = c + '0';
++  }
++
++  ts[tsN++]= ' ';
++  ts[tsN]=0;
++
++  return regexec(reg, ts, 0, 0, 0);
++}
++
++int page_len()
++{
++  return (_gtab_space_auto_first & GTAB_space_auto_first_any) ?
++  cur_inmd->M_DUP_SEL+1:cur_inmd->M_DUP_SEL;
++}
++
++static void page_no_str(char tstr[])
++{
++  if (ggg.wild_mode || ggg.gtab_buf_select) {
++    int pgN = (ggg.total_matchN + cur_inmd->M_DUP_SEL - 1) / cur_inmd->M_DUP_SEL;
++    if (pgN < 2)
++      return;
++
++    int pg = ggg.gtab_buf_select ? ggg.pg_idx : ggg.wild_page;
++    sprintf(tstr, "%d/%d", pg /cur_inmd->M_DUP_SEL + 1, pgN);
++  } else {
++    int pgN = (ggg.E1 - ggg.S1 + page_len() - 1) /page_len();
++
++    if (pgN < 2)
++      return;
++
++    sprintf(tstr, "%d/%d", (ggg.pg_idx - ggg.S1)/page_len()+1, pgN);
++  }
++}
++
++char *htmlspecialchars(char *s, char out[])
++{
++  struct {
++    char c;
++    char *str;
++  } chs[]= {{'>',"gt"}, {'<',"lt"}, {'&',"amp"}
++#if 0
++  , {' ',"nbsp"}
++#endif
++  };
++  int chsN=sizeof(chs)/sizeof(chs[0]);
++
++  int outn=0;
++  while (*s) {
++    int sz = utf8_sz(s);
++    int i;
++    for(i=0; i<chsN; i++)
++      if (chs[i].c==*s)
++        break;
++    if (i==chsN) {
++      memcpy(&out[outn],s, sz);
++      outn+=sz;
++      s+=sz;
++    }
++    else {
++      out[outn++]='&';
++      int len=strlen(chs[i].str);
++      memcpy(&out[outn], chs[i].str, len);
++      outn+=len;
++      out[outn++]=';';
++      s++;
++    }
++  }
++
++  out[outn]=0;
++  return out;
++}
++
++
++void disp_selection0(gboolean phrase_selected, gboolean force_disp)
++{
++  char pgstr[32];
++  pgstr[0]=0;
++  page_no_str(pgstr);
++
++  if (!gtab_vertical_select_on()) {
++    if (ggg.more_pg)
++      set_page_label(pgstr);
++    else
++      clear_page_label();
++  }
++
++  char tt[1024];
++  tt[0]=0;
++  char uu[MAX_CIN_PHR];
++
++  int ofs;
++  if (!ggg.wild_mode && ggg.exa_match && (_gtab_space_auto_first & GTAB_space_auto_first_any)) {
++    strcat(tt, htmlspecialchars(seltab[0], uu));
++    if (gtab_vertical_select_on())
++      strcat(tt, "\n");
++    else
++      strcat(tt, " ");
++    ofs = 1;
++  } else {
++    ofs = 0;
++  }
++
++
++  int i,max_i;
++  for(max_i = cur_inmd->M_DUP_SEL + ofs-1; max_i>=0; max_i--)
++    if (seltab[max_i][0])
++      break;
++
++  for(i=ofs; i<= max_i; i++) {
++    if (seltab[i][0]) {
++      char selback[MAX_CIN_PHR+16];
++      htmlspecialchars(seltab[i], selback);
++
++      utf8cpy(uu, &cur_inmd->selkey[i - ofs]);
++      char vvv[16];
++      char www[1024];
++      if (hime_win_color_use)
++        sprintf(www, "<span foreground=\"%s\">%s</span>", hime_sel_key_color, htmlspecialchars(uu, vvv));
++      else
++        sprintf(www, "<span foreground=\""HIME_SEL_KEY_COLOR_DEFAULT"\">%s</span>", htmlspecialchars(uu, vvv));
++      strcat(tt, www);
++
++      if (gtab_vertical_select_on())
++        strcat(tt, " ");
++
++      if (phrase_selected && i==ggg.sel1st_i) {
++        strcat(tt, "<span foreground=\"red\">");
++        strcat(strcat(tt, selback), " ");
++        strcat(tt, "</span>");
++      } else {
++        char uu[MAX_CIN_PHR];
++
++        if (gtab_vertical_select_on()) {
++          utf8cpy_bytes(uu, selback, 120);
++          strcat(tt, uu);
++        } else {
++          char *p = selback;
++
++          static char *skip[]={"http://", "ftp://", "https://", NULL};
++
++          int j;
++          for(j=0; skip[j]; j++)
++            if (!strncmp(seltab[i], skip[j], strlen(skip[j]))) {
++              p+=strlen(skip[j]);
++              break;
++            }
++
++          utf8cpy_bytes(uu, p, 6 * 3);
++          strcat(strcat(tt, uu), " ");
++        }
++      }
++
++      if (gtab_vertical_select_on())
++        strcat(tt, "\n");
++    } else {
++      extern gboolean b_use_full_space;
++
++      if (!gtab_vertical_select_on() && gtab_disp_partial_match_on()) {
++         if (b_use_full_space)
++           strcat(tt, "   ");
++         else {
++           strcat(tt, "   ");
++         }
++      }
++    }
++  }
++
++  if (gtab_vertical_select_on() && pgstr[0]) {
++    char tstr2[16];
++    sprintf(tstr2, "(%s)", pgstr);
++    strcat(tt, tstr2);
++  }
++
++  int len = strlen(tt);
++  if (len && tt[len-1] == '\n')
++    tt[len-1] = 0;
++
++  if (gtab_pre_select_or_partial_on() || ggg.wild_mode || ggg.spc_pressed || ggg.last_full || force_disp) {
++    disp_gtab_sel(tt);
++  }
++}
++
++
++void disp_selection(gboolean phrase_selected)
++{
++  disp_selection0(phrase_selected, FALSE);
++}
++
++void wildcard()
++{
++  int i,t, wild_ofs=0;
++  int found=0;
++  regex_t reg;
++
++  ClrSelArea();
++  clr_seltab();
++  /* printf("wild %d %d %d %d\n", ggg.inch[0], ggg.inch[1], ggg.inch[2], ggg.inch[3]); */
++  ggg.defselN=0;
++  char regstr[32];
++  int regstrN=0;
++
++  regstr[regstrN++]=' ';
++
++  for(i=0; i < KEY_N; i++) {
++    if (!ggg.inch[i])
++      break;
++    if (ggg.inch[i] == cur_inmd->WILD_STAR) {
++      regstr[regstrN++]='.';
++      regstr[regstrN++]='*';
++    } else
++    if (ggg.inch[i] == cur_inmd->WILD_QUES) {
++      regstr[regstrN++]='.';
++    } else {
++      char c = ggg.inch[i] + '0';         // start from '0'
++      if (strchr("*.\\()[]", c))
++      regstr[regstrN++] = '\\';
++      regstr[regstrN++]=c;
++    }
++  }
++
++  regstr[regstrN++]=' ';
++  regstr[regstrN]=0;
++
++//  dbg("regstr %s\n", regstr);
++
++  if (regcomp(&reg, regstr, 0)) {
++    dbg("regcomp failed\n");
++    return;
++  }
++
++  for(t=0; t< cur_inmd->DefChars && ggg.defselN < cur_inmd->M_DUP_SEL; t++) {
++    if (cmp_inmd_idx(&reg, t))
++      continue;
++
++    if (wild_ofs >= ggg.wild_page) {
++      load_seltab(t, ggg.defselN);
++      ggg.defselN++;
++    } else
++      wild_ofs++;
++
++    found=1;
++  } /* for t */
++
++
++  if (!found) {
++    bell_err();
++  } else
++  if (!ggg.wild_page) {
++    ggg.total_matchN = 0;
++
++    for(t=0; t< cur_inmd->DefChars; t++)
++      if (!cmp_inmd_idx(&reg, t))
++        ggg.total_matchN++;
++
++  }
++
++  if (ggg.total_matchN > cur_inmd->M_DUP_SEL)
++    ggg.more_pg = 1;
++
++  regfree(&reg);
++  disp_selection(FALSE);
++}
++
++static char *ptr_selkey(KeySym key)
++{
++  if (key>= XK_KP_0 && key<= XK_KP_9)
++    key-= XK_KP_0 - '0';
++  return strchr(cur_inmd->selkey, key);
++}
++
++
++void init_gtab_pho_query_win();
++int feedkey_pho(KeySym xkey, int state);
++
++void set_gtab_target_displayed()
++{
++  close_gtab_pho_win();
++}
++
++gboolean is_gtab_query_mode()
++{
++  return poo.same_pho_query_state == SAME_PHO_QUERY_pho_select;
++}
++
++void reset_gtab_all()
++{
++  if (!cur_inmd)
++    return;
++
++  ClrIn();
++  ClrSelArea();
++}
++
++
++static gboolean has_wild_card()
++{
++  int i;
++
++  for(i=0; i < cur_inmd->MaxPress; i++)
++    if (ggg.inch[i]>= cur_inmd->WILD_QUES) {
++      return TRUE;
++    }
++
++  return FALSE;
++}
++
++static void proc_wild_disp()
++{
++   DispInArea();
++   ggg.wild_page = 0;
++   wildcard();
++   disp_selection(0);
++}
++
++gboolean full_char_proc(KeySym keysym);
++void insert_gbuf_cursor_char(char ch);
++gboolean gtab_pre_select_shift(KeySym key, int kbstate);
++
++gboolean shift_char_proc(KeySym key, int kbstate)
++{
++    if (key >= 127)
++      return FALSE;
++
++#if 0
++    if (kbstate & LockMask) {
++      if (key >= 'a' && key <= 'z')
++        key-=0x20;
++    } else {
++      if (key >= 'A' && key <= 'Z')
++        key+=0x20;
++    }
++#endif
++
++    if (gtab_pre_select_shift(key, kbstate))
++      return TRUE;
++
++    if (current_CS->b_half_full_char)
++      return full_char_proc(key);
++
++    if (ggg.gbufN)
++      insert_gbuf_cursor_char(key);
++    else
++      send_ascii(key);
++
++    return TRUE;
++}
++
++extern GtkWidget *gwin_pho;
++gboolean feed_phrase(KeySym ksym, int state);
++int gtab_buf_backspace();
++gboolean output_gbuf();
++int show_buf_select();
++void gbuf_next_pg(), gbuf_prev_pg();
++void show_win_gtab();
++int gbuf_cursor_left();
++int gbuf_cursor_right();
++int gbuf_cursor_home();
++int gbuf_cursor_end();
++int gtab_buf_delete();
++void set_gbuf_c_sel(int v);
++void set_gtab_user_head();
++KeySym keypad_proc(KeySym xkey);
++void save_gtab_buf_phrase(KeySym key);
++gboolean save_gtab_buf_shift_enter();
++gboolean win_sym_page_up(), win_sym_page_down();
++u_int64_t vmaskci;
++gboolean gtab_pre_select_idx(int c);
++void save_CS_current_to_temp();
++void tsin_set_eng_ch(int nmod);
++
++gboolean feedkey_gtab(KeySym key, int kbstate)
++{
++  int i,j=0;
++  int inkey=0;
++  char *pselkey= NULL;
++  gboolean phrase_selected = FALSE;
++  char seltab_phrase[MAX_SELKEY];
++  gboolean is_keypad = FALSE;
++  gboolean shift_m = (kbstate & ShiftMask) > 0;
++//  gboolean ctrl_m = (kbstate & ControlMask) > 0;
++  gboolean capslock_on = (kbstate & LockMask);
++
++  bzero(seltab_phrase, sizeof(seltab_phrase));
++
++//  dbg("uuuuu %x %x   shift,ctrl:%d,%d\n", key, kbstate, shift_m, ctrl_m);
++
++  if (!cur_inmd)
++    return 0;
++
++  gboolean is_dayi = !strncmp(cur_inmd->filename, "dayi", 4);
++
++  if ((tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_CapsLock) &&
++      (key == XK_Caps_Lock)){
++    // The CapLock status may be incorrect when XK_Caps_Lock is pressed.
++    gboolean new_tsin_pho_mode = ! gdk_keymap_get_caps_lock_state(gdk_keymap_get_default());
++    if (current_CS->tsin_pho_mode != new_tsin_pho_mode) {
++      current_CS->tsin_pho_mode = new_tsin_pho_mode;
++      save_CS_current_to_temp();
++      tsin_set_eng_ch(new_tsin_pho_mode);
++    }
++  }
++
++  if ((kbstate & (Mod1Mask|Mod4Mask|Mod5Mask|ControlMask))==ControlMask
++     && key>='1' && key<='9' && ggg.gbufN) {
++    save_gtab_buf_phrase(key);
++    return 1;
++  }
++
++  if (ggg.gbufN && key==XK_Tab)
++    return 1;
++
++  if ((key==XK_Shift_L||key==XK_Shift_R) && !key_press_alt) {
++    key_press_alt = TRUE;
++    key_press_ctrl = FALSE;
++  } else if ((key==XK_Control_L||key==XK_Control_R) && !key_press_ctrl && tss.pre_selN) {
++    key_press_alt = FALSE;
++    key_press_ctrl = TRUE;
++    return TRUE;
++  } else {
++    key_press_alt = FALSE;
++    key_press_ctrl = FALSE;
++  }
++
++  if (kbstate & (Mod1Mask|Mod4Mask|Mod5Mask|ControlMask)) {
++    return 0;
++  }
++
++  if (poo.same_pho_query_state == SAME_PHO_QUERY_pho_select)
++    return feedkey_pho(key, 0);
++
++  if (poo.same_pho_query_state == SAME_PHO_QUERY_none && gwin_pho &&
++    GTK_WIDGET_VISIBLE(gwin_pho))
++     hide_win_pho();
++
++  if (!tsin_pho_mode()) {
++    if (key < 0x20 || key>=0x7f)
++      goto shift_proc;
++
++    if (capslock_on && hime_capslock_lower)
++      case_inverse((KeySym *)&key, shift_m);
++
++    if (ggg.gbufN)
++      insert_gbuf_cursor_char(key);
++    else
++      send_ascii(key);
++
++    return 1;
++  }
++
++
++  int lcase;
++  lcase = tolower(key);
++  int ucase;
++  ucase = toupper(key);
++  if (key < 127 && cur_inmd->keymap[key]) {
++    if (key < 'A' || key > 'z' || (key > 'Z'  && key < 'a') )
++      goto shift_proc;
++    if (cur_inmd->keymap[lcase] != cur_inmd->keymap[ucase])
++      goto next;
++  }
++
++
++shift_proc:
++  if (shift_m && !strchr(cur_inmd->selkey, key) && !ggg.more_pg && key>=' ' && key < 0x7e &&
++      key!='*' && (key!='?' || (gtab_shift_phrase_key && !ggg.ci))) {
++    if (gtab_shift_phrase_key) {
++      if (tss.pre_selN && shift_char_proc(key, kbstate))
++        return TRUE;
++      if (feed_phrase(key, kbstate))
++        return TRUE;
++    } else {
++      if (!cur_inmd->keymap[key] || (lcase != ucase &&
++           cur_inmd->keymap[lcase]==cur_inmd->keymap[ucase]))
++        return shift_char_proc(key, kbstate);
++    }
++  }
++
++  gboolean has_wild;
++  has_wild = FALSE;
++
++  switch (key) {
++    case XK_BackSpace:
++      ggg.last_idx=0;
++      ggg.spc_pressed=0;
++      ggg.sel1st_i=MAX_SELKEY-1;
++      clear_gtab_input_error_color();
++      hide_gtab_pre_sel();
++
++      if (ggg.ci==0) {
++        if (AUTO_SELECT_BY_PHRASE)
++          return gtab_buf_backspace();
++        else
++          return 0;
++      }
++
++      if (ggg.ci>0)
++        ggg.inch[--ggg.ci]=0;
++
++      if (has_wild_card()) {
++        proc_wild_disp();
++        return 1;
++      }
++
++
++      ggg.wild_mode=0;
++      ggg.invalid_spc = FALSE;
++      if (ggg.ci==1 && cur_inmd->use_quick) {
++        int i;
++        clr_seltab();
++        for(i=0;i<cur_inmd->M_DUP_SEL;i++)
++          utf8cpy(seltab[i], (char *)cur_inmd->qkeys->quick1[ggg.inch[0]-1][i]);
++
++        ggg.defselN=cur_inmd->M_DUP_SEL;
++        DispInArea();
++        goto Disp_opt;
++      } else
++      if (ggg.ci==2 && cur_inmd->use_quick) {
++        int i;
++        clr_seltab();
++        for(i=0;i<cur_inmd->M_DUP_SEL;i++)
++          utf8cpy(seltab[i], (char *)cur_inmd->qkeys->quick2[ggg.inch[0]-1][ggg.inch[1]-1][i]);
++
++        ggg.defselN=cur_inmd->M_DUP_SEL;
++        DispInArea();
++        goto Disp_opt;
++      }
++
++      break;
++    case XK_KP_Enter:
++    case XK_Return:
++      if (AUTO_SELECT_BY_PHRASE) {
++        hide_gtab_pre_sel();
++        if (shift_m) {
++          return save_gtab_buf_shift_enter();
++        } else
++          return output_gbuf();
++      }
++      else
++        return 0;
++    case XK_Up:
++      if (gtab_has_input())
++        return TRUE;
++      return FALSE;
++    case XK_Down:
++    case XK_KP_Down:
++      if (AUTO_SELECT_BY_PHRASE)
++        return show_buf_select();
++      else
++        return 0;
++    case XK_Escape:
++      hide_gtab_pre_sel();
++      if (ggg.gtab_buf_select) {
++        ggg.gtab_buf_select = 0;
++        reset_gtab_all();
++        ClrSelArea();
++        if (hime_pop_up_win && !gtab_has_input())
++          hide_win_gtab();
++        return 1;
++      }
++      ClrSelArea();
++      close_gtab_pho_win();
++      if (ggg.ci) {
++        reset_gtab_all();
++        return 1;
++      } else {
++        if (ggg.gbufN) {
++          set_gtab_user_head();
++          return 1;
++        }
++        ClrIn();
++        return 0;
++      }
++    case XK_Prior:
++    case XK_KP_Prior:
++    case XK_KP_Subtract:
++      if (ggg.wild_mode) {
++        if (ggg.wild_page >= cur_inmd->M_DUP_SEL) ggg.wild_page-=cur_inmd->M_DUP_SEL;
++        wildcard();
++        return 1;
++      } else
++      if (ggg.more_pg) {
++        if (ggg.gtab_buf_select) {
++          gbuf_prev_pg();
++          return 1;
++        }
++
++        ggg.pg_idx -= page_len();
++        if (ggg.pg_idx < ggg.S1)
++          ggg.pg_idx = ggg.S1;
++
++        goto next_pg;
++      }
++
++      if (key==XK_KP_Subtract)
++        goto keypad_proc;
++
++      return win_sym_page_up();
++    case XK_Next:
++    case XK_KP_Next:
++    case XK_KP_Add:
++      if (ggg.more_pg) {
++        if (ggg.gtab_buf_select) {
++          gbuf_next_pg();
++          return 1;
++        }
++next_page:
++//        dbg("more...\n");
++        ggg.pg_idx += page_len();
++        if (ggg.pg_idx >=ggg.E1)
++          ggg.pg_idx = ggg.S1;
++        goto next_pg;
++      } else {
++        if (key==XK_KP_Add)
++          goto keypad_proc;
++        if (win_sym_page_down())
++          return TRUE;
++        if (!ggg.gtab_buf_select && ggg.gbufN && AUTO_SELECT_BY_PHRASE)
++          return show_buf_select();
++        return FALSE;
++      }
++    case ' ':
++      hide_gtab_pre_sel();
++
++      if (ggg.invalid_spc && gtab_invalid_key_in)
++        ClrIn();
++
++      if (!gtab_invalid_key_in && ggg.spc_pressed && ggg.invalid_spc) {
++        ClrIn();
++        return 1;
++      }
++
++      has_wild = has_wild_card();
++
++//      dbg("ggg.wild_mode:%d ggg.more_pg:%d ggg.ci:%d  has_wild:%d\n", ggg.wild_mode, ggg.more_pg, ggg.ci, has_wild);
++
++      if (ggg.wild_mode) {
++        // request from tetralet
++        if (!ggg.wild_page && ggg.total_matchN < cur_inmd->M_DUP_SEL) {
++          ggg.sel1st_i = 0;
++          goto direct_select;
++        }
++
++        ggg.wild_page += cur_inmd->M_DUP_SEL;
++        if (ggg.wild_page >= ggg.total_matchN)
++          ggg.wild_page=0;
++
++        wildcard();
++        ggg.spc_pressed = TRUE;
++        return 1;
++      } else
++      if (ggg.more_pg && !(_gtab_space_auto_first & GTAB_space_auto_first_any)) {
++        if (ggg.gtab_buf_select) {
++          gbuf_next_pg();
++          return 1;
++        }
++        else
++          goto next_page;
++      } else
++      if (ggg.ci==0) {
++        if (current_CS->b_half_full_char)
++          return full_char_proc(key);
++
++        if (ggg.gbufN) {
++          output_gbuf();
++        } else
++          return 0;
++      } else
++      if (!has_wild) {
++//        dbg("iii %d  ggg.defselN:%d   %d\n", ggg.sel1st_i, ggg.defselN, cur_inmd->M_DUP_SEL);
++        if (_gtab_space_auto_first == GTAB_space_auto_first_any && seltab[0][0] &&
++            ggg.sel1st_i==MAX_SELKEY-1) {
++          ggg.sel1st_i = 0;
++        }
++
++        if (_gtab_space_auto_first == GTAB_space_auto_first_nofull && ggg.exa_match > 1
++            && !AUTO_SELECT_BY_PHRASE && gtab_dup_select_bell)
++          bell();
++
++        if (seltab[ggg.sel1st_i][0]) {
++//          dbg("ggg.last_full %d %d\n", ggg.last_full,ggg.spc_pressed);
++          if (gtab_full_space_auto_first || ggg.spc_pressed) {
++direct_select:
++            if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input) {
++//              dbg("ins ggg.kval %x\n", ggg.kval);
++              insert_gbuf_cursor1_cond(seltab[ggg.sel1st_i], ggg.kval, ggg.exa_match);
++            }
++            else
++              putstr_inp(seltab[ggg.sel1st_i]);  /* select 1st */
++            return 1;
++          }
++        }
++      }
++
++      ggg.last_full=0;
++      ggg.spc_pressed=1;
++//      dbg("spc_pressed=1\n");
++
++      if (has_wild) {
++        ggg.wild_page=0;
++        ggg.wild_mode=1;
++        wildcard();
++        return 1;
++      }
++
++      break;
++    case '?':
++    case '*':
++      if ((!gtab_que_wild_card && key == '?') || (!gtab_que_wild_card_asterisk && key == '*')) {
++        inkey=cur_inmd->keymap[key];
++        if ((inkey && (inkey!=cur_inmd->WILD_QUES && inkey!=cur_inmd->WILD_STAR)) || ptr_selkey(key))
++          goto next;
++        if (AUTO_SELECT_BY_PHRASE && ggg.gbufN) {
++          insert_gbuf_cursor_char(key);
++          return 1;
++        } else {
++          if (current_CS->b_half_full_char)
++            return full_char_proc(key);
++	  else
++            return 0;
++	}
++      }
++      if (tss.pre_selN && shift_char_proc(key, kbstate))
++        return TRUE;
++
++      // if (current_CS->b_half_full_char)
++      //  return full_char_proc(key);
++
++      inkey=cur_inmd->keymap[key];
++      if ((inkey && (inkey!=cur_inmd->WILD_STAR && inkey!=cur_inmd->WILD_QUES)) || ptr_selkey(key)) {
++//        dbg("%d %d\n", inkey, cur_inmd->WILD_STAR);
++        goto next;
++      }
++      if (ggg.ci< cur_inmd->MaxPress) {
++        ggg.inch[ggg.ci++]=inkey;
++        DispInArea();
++
++        if (hime_pop_up_win)
++          show_win_gtab();
++
++        ggg.total_matchN = 0;
++        ggg.wild_page=0;
++        ggg.wild_mode=1;
++        wildcard();
++        return 1;
++      }
++      return 0;
++    case XK_Left:
++    case XK_KP_Left:
++      return gbuf_cursor_left();
++    case XK_Right:
++    case XK_KP_Right:
++      return gbuf_cursor_right();
++    case XK_Home:
++    case XK_KP_Home:
++      return gbuf_cursor_home();
++    case XK_End:
++    case XK_KP_End:
++      return gbuf_cursor_end();
++    case XK_Delete:
++    case XK_KP_Delete:
++      return gtab_buf_delete();
++    case XK_Shift_L:
++    case XK_Shift_R:
++    case XK_Control_R:
++    case XK_Control_L:
++    case XK_Alt_L:
++    case XK_Alt_R:
++    case XK_Caps_Lock:
++      return 0;
++    case '`':
++      if (gtab_pho_query && !cur_inmd->keymap[key]) {
++        poo.same_pho_query_state = SAME_PHO_QUERY_gtab_input;
++        reset_gtab_all();
++        disp_gtab_sel(_("輸入要查的同音字,接著在注音視窗選字"));
++        if (hime_pop_up_win)
++          show_win_gtab();
++        disp_pho_sel("");
++        init_gtab_pho_query_win();
++        return 1;
++      }
++    default:
++next:
++
++      if (key < 0x7f)
++        inkey= cur_inmd->keymap[key];
++      else
++        inkey = 0;
++
++      if (shift_m && !inkey && !tss.ctrl_pre_sel &&
++        tss.pre_selN && shift_char_proc(key, kbstate))
++        return TRUE;
++
++      clear_gtab_input_error_color();
++
++      if (ggg.invalid_spc && gtab_invalid_key_in) {
++        ClrIn();
++      }
++      if (key>=XK_KP_0 && key<=XK_KP_9) {
++        if (!ggg.ci) {
++          if (ggg.gbufN) {
++            insert_gbuf_cursor_char(key - XK_KP_0 + '0');
++            return 1;
++          } else
++            return 0;
++        }
++        if (is_dayi) {
++          key = key - XK_KP_0 + '0';
++          is_keypad = TRUE;
++        }
++      }
++
++      int keypad;
++keypad_proc:
++      keypad = keypad_proc(key);
++      if (keypad) {
++        if (!ggg.ci) {
++          if (ggg.gbufN) {
++            insert_gbuf_cursor_char(keypad);
++            return 1;
++          } else
++            return 0;
++        }
++      }
++      char *pendkey = strchr(cur_inmd->endkey, key);
++
++      pselkey=ptr_selkey(key);
++
++      if (!pselkey && (key < 32 || key > 0x7e) && (gtab_full_space_auto_first || ggg.spc_pressed)) {
++//        dbg("%x %x ggg.sel1st_i:%d  '%c'\n", pselkey, key, ggg.sel1st_i, seltab[ggg.sel1st_i][0]);
++        if (seltab[ggg.sel1st_i][0]) {
++          if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++            insert_gbuf_cursor1_cond(seltab[ggg.sel1st_i], ggg.kval, ggg.exa_match);
++          else
++            putstr_inp(seltab[ggg.sel1st_i]);  /* select 1st */
++        }
++
++        return 0;
++      }
++
++
++
++//        dbg("ggg.spc_pressed %d %d %d is_keypad:%d\n", ggg.spc_pressed, ggg.last_full, cur_inmd->MaxPress, is_keypad);
++
++#if 1 // for dayi, testcase :  6 space keypad6
++      int vv = pselkey - cur_inmd->selkey;
++      if (pselkey && tss.pre_selN && !ggg.gtab_buf_select && (tss.ctrl_pre_sel||
++          ((!inkey||ggg.spc_pressed||is_keypad)&&! gtab_disp_partial_match_on() && !gtab_pre_select_on()))) {
++        if (gtab_pre_select_idx(vv))
++          return TRUE;
++      } else
++      if (( (ggg.spc_pressed||ggg.last_full||is_keypad) ||(ggg.wild_mode && (!inkey ||pendkey)) || ggg.gtab_buf_select) && pselkey) {
++        if ((_gtab_space_auto_first & GTAB_space_auto_first_any) && !ggg.wild_mode)
++          vv++;
++
++        if (vv<0)
++          vv=9;
++
++        if (seltab[vv][0]) {
++          if (AUTO_SELECT_BY_PHRASE && !same_query_show_pho_win()) {
++            if (ggg.gtab_buf_select && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++              set_gbuf_c_sel(vv);
++            else
++              insert_gbuf_cursor1_cond(seltab[vv], ggg.kval, ggg.exa_match);
++          }
++          else {
++            putstr_inp(seltab[vv]);
++          }
++
++          if (hime_pop_up_win && !gtab_has_input())
++            hide_win_gtab();
++
++          return 1;
++        }
++      }
++#endif
++
++//      dbg("iii %x sel1st_i:%d auto:%d\n", pselkey, ggg.sel1st_i, AUTO_SELECT_BY_PHRASE);
++      if (seltab[ggg.sel1st_i][0] && !ggg.wild_mode &&
++           (gtab_full_space_auto_first||ggg.spc_pressed||ggg.last_full) ) {
++        if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++          insert_gbuf_cursor1_cond(seltab[ggg.sel1st_i], ggg.kval, ggg.exa_match);
++        else
++          putstr_inp(seltab[ggg.sel1st_i]);  /* select 1st */
++      }
++#if 0
++      if (key > 0x7f) {
++        return 0;
++      }
++#endif
++
++      ggg.spc_pressed=0;
++
++      // for cj & boshiamy to input digits
++      if (!ggg.ci && !inkey) {
++        if (current_CS->b_half_full_char)
++          return full_char_proc(key);
++        else {
++          if (ggg.gbufN && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input) {
++            insert_gbuf_cursor_char(key);
++            return 1;
++          }
++          else
++            return 0;
++        }
++      }
++
++      if (ggg.wild_mode && inkey>=1 && ggg.ci< cur_inmd->MaxPress) {
++        ggg.inch[ggg.ci++]=inkey;
++        if (hime_pop_up_win)
++          show_win_gtab();
++        proc_wild_disp();
++        return 1;
++      }
++
++      if (inkey>=1 && ggg.ci< cur_inmd->MaxPress) {
++        ggg.inch[ggg.ci++]=inkey;
++        hide_gtab_pre_sel();
++
++        if (hime_pop_up_win)
++          show_win_gtab();
++        ggg.last_full=0;
++
++        if (cur_inmd->use_quick && !pendkey) {
++          if (ggg.ci==1) {
++            int i;
++            for(i=0;i < cur_inmd->M_DUP_SEL; i++) {
++              utf8cpy(seltab[i], (char *)&cur_inmd->qkeys->quick1[inkey-1][i]);
++            }
++
++            ggg.defselN=cur_inmd->M_DUP_SEL;
++            DispInArea();
++            goto Disp_opt;
++          } else
++          if (ggg.ci==2 && !pselkey) {
++            int i;
++            for(i=0;i < cur_inmd->M_DUP_SEL; i++) {
++              utf8cpy(seltab[i], (char *)&cur_inmd->qkeys->quick2[ggg.inch[0]-1][inkey-1][i]);
++            }
++
++            ggg.defselN=cur_inmd->M_DUP_SEL;
++            DispInArea();
++            goto Disp_opt;
++          }
++        }
++      } else
++      if (ggg.ci == cur_inmd->MaxPress && !pselkey) {
++        bell();
++        return 1;
++      }
++
++
++      if (inkey) {
++        for(i=0; i < MAX_TAB_KEY_NUM64_6; i++)
++          if (ggg.inch[i]>=cur_inmd->WILD_QUES) {
++            DispInArea();
++            if (ggg.ci==cur_inmd->MaxPress) {
++              ggg.wild_mode=1;
++              ggg.wild_page=0;
++              wildcard();
++            }
++
++            return 1;
++          }
++      } else {
++        if (!pselkey) {
++          if (current_CS->b_half_full_char)
++            return full_char_proc(key);
++          else {
++            if (key>=' ' && key<0x7f && AUTO_SELECT_BY_PHRASE && ggg.gbufN)
++              insert_gbuf_cursor_char(key);
++            else
++              return 0;
++          }
++        }
++
++        if (ggg.defselN) {
++          goto YYYY;
++        }
++     }
++  } /* switch */
++
++
++  if (ggg.ci==0) {
++    ClrSelArea();
++    ClrIn();
++    return 1;
++  }
++
++  ggg.invalid_spc = FALSE;
++  char *pendkey = NULL;
++  pendkey = strchr(cur_inmd->endkey, key);
++
++  DispInArea();
++
++  ggg.kval=0;
++
++  for(i=0; i < Max_tab_key_num; i++) {
++    ggg.kval|= (u_int64_t)ggg.inch[i] << (KeyBits * (Max_tab_key_num - 1 - i));
++  }
++
++#if 1
++  if (ggg.last_idx)
++    ggg.S1=ggg.last_idx;
++  else
++#endif
++    ggg.S1=cur_inmd->idx1[ggg.inch[0]];
++
++//  dbg("--------- ch:%d %d val %llx  ggg.S1:%d\n", ggg.inch[0], Max_tab_key_num, ggg.kval, ggg.S1);
++
++  int oE1;
++  oE1=cur_inmd->idx1[ggg.inch[0]+1];
++  if (cur_inmd->keybits==6)
++    vmaskci = cur_inmd->key64 ? vmask64[ggg.ci]:vmask[ggg.ci];
++  else
++    vmaskci = cur_inmd->key64 ? vmask64_7[ggg.ci]:vmask_7[ggg.ci];
++
++  gtab_scan_pre_select(TRUE);
++
++  while ((CONVT2(cur_inmd, ggg.S1) & vmaskci) != ggg.kval &&
++          CONVT2(cur_inmd, ggg.S1) < ggg.kval &&  ggg.S1<oE1)
++    ggg.S1++;
++
++  ggg.pg_idx=ggg.last_idx=ggg.S1;
++
++
++#if 0
++  dbg("MaxPress:%d vmaskci:%llx kval:%llx ggg.ci:%d  !=%d  S1:%d  kval:%x\n", cur_inmd->MaxPress,
++  vmaskci, ggg.kval, ggg.ci,
++  ((CONVT2(cur_inmd, ggg.S1) & vmaskci)!=ggg.kval), ggg.S1);
++#endif
++
++  if ((CONVT2(cur_inmd, ggg.S1) & vmaskci)!=ggg.kval || (ggg.wild_mode && ggg.defselN) ||
++                  ((/* ggg.ci==cur_inmd->MaxPress|| */ ggg.spc_pressed) && ggg.defselN &&
++      (pselkey && ( pendkey || ggg.spc_pressed)) ) ) {
++YYYY:
++
++    if ((pselkey || ggg.wild_mode) && ggg.defselN) {
++      int vv = pselkey - cur_inmd->selkey;
++
++      if ((_gtab_space_auto_first & GTAB_space_auto_first_any) && !ggg.wild_mode
++          && ggg.exa_match && (!cur_inmd->use_quick || ggg.ci!=2))
++        vv++;
++
++      if (vv<0)
++        vv=9;
++
++      if (seltab[vv][0]) {
++        if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++          insert_gbuf_cursor1_cond(seltab[vv], ggg.kval, ggg.exa_match);
++        else
++          putstr_inp(seltab[vv]);
++        return 1;
++      }
++    }
++
++    if (pselkey && !ggg.defselN)
++      return 0;
++
++    if (gtab_invalid_key_in) {
++      if (ggg.spc_pressed) {
++        bell_err();
++        ggg.invalid_spc = TRUE;
++//        dbg("ggg.invalid_spc\n");
++      } else {
++        seltab[0][0]=0;
++        ClrSelArea();
++      }
++    } else {
++      if (gtab_dup_select_bell)
++        bell();
++
++      if (ggg.ci>0)
++        ggg.inch[--ggg.ci]=0;
++    }
++
++    ggg.last_idx=0;
++    DispInArea();
++    return 1;
++  }
++
++//refill:
++
++  j=ggg.S1;
++  while(CONVT2(cur_inmd, j)==ggg.kval && j<oE1)
++    j++;
++
++  ggg.E1 = j;
++  ggg.total_matchN = ggg.E1 - ggg.S1;
++  ggg.pg_idx = ggg.S1;
++
++  ggg.more_pg = 0;
++  if (ggg.total_matchN > page_len()) {
++    if ((_gtab_space_auto_first & GTAB_space_auto_first_any) || ggg.spc_pressed || pendkey ||
++      (ggg.ci==cur_inmd->MaxPress && (_gtab_space_auto_first & GTAB_space_auto_first_full)))
++      ggg.more_pg = 1;
++  }
++
++  if (ggg.ci < cur_inmd->MaxPress && !ggg.spc_pressed && !pendkey && !ggg.more_pg) {
++    j = ggg.S1;
++    ggg.exa_match=0;
++    clr_seltab();
++    int match_cnt=0;
++
++    while (CONVT2(cur_inmd, j)==ggg.kval && ggg.exa_match <= page_len()) {
++      seltab_phrase[ggg.exa_match] = load_seltab(j, ggg.exa_match);
++      match_cnt++;
++      ggg.exa_match++;
++      j++;
++    }
++
++    ggg.defselN=ggg.exa_match;
++//    dbg("--- ggg.exa_match %d\n", ggg.exa_match);
++
++    if (ggg.defselN > page_len())
++      ggg.defselN--;
++
++    int shiftb=(KEY_N - 1 -ggg.ci) * KeyBits;
++
++//    if (gtab_disp_partial_match_on)
++    while((CONVT2(cur_inmd, j) & vmaskci)==ggg.kval && j<oE1) {
++      int fff=cur_inmd->keycol[(CONVT2(cur_inmd, j)>>shiftb) & cur_inmd->kmask];
++      u_char *tbl_ch = tblch(j);
++
++      if (gtab_disp_partial_match_on() && (!seltab[fff][0] || seltab_phrase[fff] ||
++           (bchcmp(seltab[fff], tbl_ch)>0 && fff > ggg.exa_match))) {
++        seltab_phrase[fff] = load_seltab(j, fff);
++        ggg.defselN++;
++      }
++
++      match_cnt++;
++#if 0
++      dbg("jj %d", fff); utf8_putchar(seltab[fff]); dbg("\n");
++#endif
++      j++;
++    }
++
++    if (gtab_unique_auto_send_on()) {
++      char *first_str=NULL;
++      for(i=0; i < page_len(); i++) {
++        if (!seltab[i][0])
++          continue;
++        if (!first_str)
++          first_str = seltab[i];
++      }
++
++      if (match_cnt==1 && first_str) {
++        if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++          insert_gbuf_nokey(first_str);
++        else
++          putstr_inp(first_str);
++        return 1;
++      }
++    }
++  } else {
++//    dbg("more %d %d  skip_end:%d\n", ggg.more_pg,  ggg.total_matchN, cur_inmd->flag&FLAG_PHRASE_AUTO_SKIP_ENDKEY);
++next_pg:
++    ggg.defselN=0;
++    clr_seltab();
++    if (pendkey && (!(cur_inmd->flag&FLAG_PHRASE_AUTO_SKIP_ENDKEY) || !AUTO_SELECT_BY_PHRASE || ggg.ci==1)) {
++//      dbg("spc_pressed = 1\n");
++      ggg.spc_pressed = 1;
++    }
++
++    if (ggg.ci==cur_inmd->MaxPress)
++      ggg.last_full=1;
++    int full_send = gtab_press_full_auto_send_on() && ggg.last_full;
++
++//    dbg("flag %d\n",!(pendkey && (cur_inmd->flag&FLAG_PHRASE_AUTO_SKIP_ENDKEY)));
++    if (AUTO_SELECT_BY_PHRASE && !(pendkey && (cur_inmd->flag&FLAG_PHRASE_AUTO_SKIP_ENDKEY))
++        && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input &&
++        (ggg.spc_pressed||full_send)) {
++      j = ggg.S1;
++      int selN=0;
++      char **sel = NULL;
++
++//     puts("kkkkkkkkkkk");
++      while(j<ggg.E1 && CONVT2(cur_inmd, j)==ggg.kval && selN < 255) {
++        sel = trealloc(sel, char *, selN+1);
++        sel[selN++] = load_tblidx(j);
++        j++;
++      }
++      insert_gbuf_cursor(sel, selN, ggg.kval, FALSE);
++      gtab_scan_pre_select(FALSE);
++      clear_after_put();
++      return 1;
++    } else {
++      j = ggg.pg_idx;
++
++//      dbg("jjjjjjjjjjjjjjjjjj");
++      while(j<ggg.E1 && CONVT2(cur_inmd, j)==ggg.kval && ggg.defselN < page_len()) {
++        load_seltab(j, ggg.defselN);
++
++        j++; ggg.defselN++;
++
++        if (ggg.ci == cur_inmd->MaxPress || ggg.spc_pressed) {
++          ggg.sel1st_i=0;
++//          dbg("ggg.sel1st_i %d %d %d\n", ggg.ci, cur_inmd->MaxPress, ggg.spc_pressed);
++        }
++      }
++    }
++
++    ggg.exa_match = ggg.defselN;
++//    dbg("ggg.defselN %d\n", ggg.defselN);
++
++
++    if (ggg.defselN==1 && !ggg.more_pg) {
++      if (ggg.spc_pressed || full_send || gtab_unique_auto_send_on()) {
++        if (AUTO_SELECT_BY_PHRASE && poo.same_pho_query_state != SAME_PHO_QUERY_gtab_input)
++          insert_gbuf_cursor1_cond(seltab[0], ggg.kval, ggg.exa_match);
++        else
++          putstr_inp(seltab[0]);
++        return 1;
++      }
++    } else
++    if (!ggg.defselN) {
++      bell_err();
++//      ggg.spc_pressed=0;
++//      if (gtab_invalid_key_in)
++      {
++        ggg.invalid_spc = TRUE;
++        return TRUE;
++      }
++
++      return TRUE;
++    } else
++    if (!ggg.more_pg) {
++      if (gtab_dup_select_bell && (gtab_disp_partial_match_on() || gtab_pre_select_or_partial_on())) {
++        if (ggg.spc_pressed || gtab_full_space_auto_first || (ggg.last_full && gtab_press_full_auto_send_on()))
++          bell();
++      }
++    }
++  }
++
++Disp_opt:
++  if (gtab_disp_partial_match_on() || gtab_pre_select_or_partial_on() || ((ggg.exa_match > 1 || ggg.more_pg) &&
++    (ggg.spc_pressed || gtab_press_full_auto_send_on() ||
++    (ggg.ci==cur_inmd->MaxPress && (_gtab_space_auto_first & GTAB_space_auto_first_full))) ) ) {
++       disp_selection(phrase_selected);
++  }
++
++  return 1;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/gtab.h b/src/plugins/platforminputcontexts/hime/include/gtab.h
+new file mode 100644
+index 0000000..a30b937
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/gtab.h
+@@ -0,0 +1,167 @@
++/* Copyright (C) 2004-2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef enum {
++  GTAB_space_auto_first_none=0,   // use the value set by .cin
++  GTAB_space_auto_first_any=1,    // boshiamy, dayi
++  GTAB_space_auto_first_full=2,   // simplex
++  GTAB_space_auto_first_nofull=4,  // windows ar30 cj
++  GTAB_space_auto_first_dayi=8    // dayi: input:2   select:1
++} GTAB_space_pressed_E;
++
++typedef struct {
++  u_char key[4];   /* If I use u_long key, the struc size will be 8 */
++  u_char ch[CH_SZ];
++} ITEM;
++
++typedef struct {
++  u_char key[8];   /* If I use u_long key, the struc size will be 8 */
++  u_char ch[CH_SZ];
++} ITEM64;
++
++typedef struct {
++  char quick1[46][10][CH_SZ];
++  char quick2[46][46][10][CH_SZ];
++} QUICK_KEYS;
++
++
++enum {
++  FLAG_KEEP_KEY_CASE=1,
++  FLAG_GTAB_SYM_KBM=2, // auto close, auto switch to default input method
++  FLAG_PHRASE_AUTO_SKIP_ENDKEY=4,
++  FLAG_AUTO_SELECT_BY_PHRASE=8,
++  FLAG_GTAB_DISP_PARTIAL_MATCH=0x10,
++  FLAG_GTAB_DISP_FULL_MATCH=0x20,
++  FLAG_GTAB_VERTICAL_SELECTION=0x40,
++  FLAG_GTAB_PRESS_FULL_AUTO_SEND=0x80,
++  FLAG_GTAB_UNIQUE_AUTO_SEND=0x100,
++};
++
++enum {
++  GTAB_OPTION_AUTO=0,
++  GTAB_OPTION_YES=1,
++  GTAB_OPTION_NO=2,
++};
++
++
++#define MAX_SELKEY 16
++
++struct TableHead {
++  int version;
++  u_int flag;
++  char cname[32];         /* prompt */
++  char selkey[12];        /* select keys */
++  GTAB_space_pressed_E space_style;
++  int KeyS;               /* number of keys needed */
++  int MaxPress;           /* Max len of keystroke  ar30:4  changjei:5 */
++  int M_DUP_SEL;          /* how many keys used to select */
++  int DefC;               /* Defined characters */
++  QUICK_KEYS qkeys;
++
++  union {
++    struct {
++      char endkey[99];
++      char keybits;
++      char selkey2[10];
++    };
++
++    char dummy[128];  // for future use
++  };
++};
++
++
++#define KeyBits1(inm) (inm->keybits)
++#define KeyBits (cur_inmd->keybits)
++#define MAX_GTAB_KEYS (1<<KeyBits)
++
++#define MAX_TAB_KEY_NUM (32/KeyBits)
++#define MAX_TAB_KEY_NUM1(inm) (32/KeyBits1(inm))
++#define MAX_TAB_KEY_NUM64 (64/KeyBits)
++#define MAX_TAB_KEY_NUM641(inm) (64/KeyBits1(inm))
++
++struct _HIME_module_callback_functions;
++typedef u_int gtab_idx1_t;
++
++typedef struct {
++  ITEM *tbl;
++  ITEM64 *tbl64;
++  QUICK_KEYS *qkeys;
++  int use_quick;
++  u_int flag;
++#define MAX_CNAME (4*CH_SZ+1)
++  char *cname;
++  char *keycol;
++  int KeyS;               /* number of keys needed */
++  int MaxPress;           /* Max len of keystrike  ar30:5  changjei:5 */
++  int DefChars;           /* defined chars */
++  char *keyname; // including ?*
++  char *keyname_lookup; // used by boshiamy only
++  gtab_idx1_t *idx1;
++  char *keymap;
++  char *selkey;
++  u_char *sel1st;
++  int M_DUP_SEL;
++  int phrnum;
++  int *phridx;
++  char *phrbuf;
++  char *filename, *filename_append;
++  time_t file_modify_time;
++  gboolean key64; // db is 64 bit-long key
++  gboolean disabled; // will not be display in the selection menu
++  int max_keyN;
++  char *endkey;       // only pinin/ar30 use it
++  GTAB_space_pressed_E space_style;
++  char *icon;
++  u_char kmask, keybits, last_k_bitn, method_type;
++  char WILD_QUES, WILD_STAR;
++  struct _HIME_module_callback_functions *mod_cb_funcs;
++  char key_ch, in_cycle;
++} INMD;
++
++enum {
++  method_type_GTAB=1,
++  method_type_PHO=3,
++  method_type_TSIN=6,
++  method_type_MODULE=12,
++  method_type_SYMBOL_TABLE=13,
++  method_type_EN=14,
++};
++
++extern INMD *inmd;
++extern int inmdN;
++
++u_int64_t CONVT2(INMD *inmd, int i);
++extern INMD *cur_inmd;
++void load_gtab_list(gboolean);
++char current_method_type();
++
++#define LAST_K_bitN (cur_inmd->last_k_bitn)
++
++#define KEY_MASK ((1<<cur_inmd->keybits)-1);
++
++
++#define GTAB_LIST "gtab.list"
++
++#if 1
++#define NEED_SWAP (__BYTE_ORDER == __BIG_ENDIAN && 0)
++#else
++#define NEED_SWAP (1)
++#endif
++
++#define tblch2(inm, i) (inm->key64 ? inm->tbl64[i].ch:inm->tbl[i].ch)
++#define Max_tab_key_num1(inm) (inm->key64 ? MAX_TAB_KEY_NUM641(inm) : MAX_TAB_KEY_NUM1(inm))
++#define Max_tab_key_num Max_tab_key_num1(cur_inmd)
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime-conf.c b/src/plugins/platforminputcontexts/hime/include/hime-conf.c
+new file mode 100644
+index 0000000..527ed91
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime-conf.c
+@@ -0,0 +1,246 @@
++/* Copyright (C) 2010 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include <dirent.h>
++#include <X11/Xatom.h>
++#include <glib.h>
++
++#if !CLIENT_LIB
++char *TableDir=HIME_TABLE_DIR;
++GKeyFile *hime_omni_config = NULL;
++#define HIME_CONF "/hime.conf"
++
++void init_TableDir()
++{
++  char *dname;
++  if ((dname=getenv("HIME_TABLE_DIR"))) {
++    TableDir = dname;
++    return;
++  }
++}
++
++
++void get_hime_dir(char *tt)
++{
++    char *home = getenv("HOME");
++    if (!home)
++      home = "";
++    strcpy(tt,home);
++    strcat(tt,"/.config/hime");
++}
++
++void init_omni_config(void)
++{
++  char omni_config_fname[256];
++  int len;
++  GError *error = NULL;
++
++  if (hime_omni_config)
++    return;
++
++  memset(omni_config_fname, 0, 256);
++  get_hime_dir(omni_config_fname);
++  len = strlen(omni_config_fname);
++  snprintf(omni_config_fname + len, 256 - len, HIME_CONF);
++
++  hime_omni_config = g_key_file_new();
++  /* Ignore error */
++  g_key_file_load_from_file(hime_omni_config, omni_config_fname, 0, &error);
++}
++
++void free_omni_config(void)
++{
++  if (hime_omni_config) {
++    g_key_file_free(hime_omni_config);
++    hime_omni_config = NULL;
++  }
++}
++
++void save_omni_config(void)
++{
++  char omni_config_fname[256];
++  int len;
++  FILE *f;
++  gchar *buff;
++  gsize bufflen;
++  GError *error = NULL;
++
++  if (NULL == hime_omni_config)
++    return;
++
++  memset(omni_config_fname, 0, 256);
++  get_hime_dir(omni_config_fname);
++  len = strlen(omni_config_fname);
++  snprintf(omni_config_fname + len, 256 - len, HIME_CONF);
++  f = fopen(omni_config_fname, "w");
++  if (f) {
++    buff = g_key_file_to_data(hime_omni_config, &bufflen, &error);
++    if (NULL == buff)
++      return;
++    fwrite(buff, 1, bufflen, f);
++    fclose(f);
++    g_free(buff);
++  }
++}
++
++gboolean get_hime_user_fname(char *name, char fname[])
++{
++  get_hime_dir(fname);
++  strcat(strcat(fname,"/"),name);
++  return !access(fname, R_OK);
++//  dbg("get_hime_user_fname %s %s\n", name, fname);
++}
++
++void get_hime_conf_fname(char *name, char fname[])
++{
++  get_hime_dir(fname);
++  strcat(strcat(fname,"/config/"),name);
++}
++
++void get_hime_user_or_sys_fname(char *name, char fname[])
++{
++  if (!getenv("HIME_TABLE_DIR")) {
++    if (get_hime_user_fname(name, fname))
++      return;
++  }
++
++  get_sys_table_file_name(name, fname);
++}
++
++void get_hime_conf_str(char *name, char **rstr, char *default_str)
++{
++  char fname[MAX_HIME_STR];
++  char out[256];
++
++  if (*rstr)
++    free(*rstr);
++
++  *rstr = g_key_file_get_string(hime_omni_config, "HIME", name, NULL);
++  if (NULL != *rstr) {
++    return;
++  }
++
++  /* Compatible for previous configuration */
++  get_hime_conf_fname(name, fname);
++
++  FILE *fp;
++
++  if ((fp=fopen(fname, "rb")) == NULL) {
++    *rstr = strdup(default_str);
++    return;
++  }
++
++  myfgets(out, sizeof(out), fp);
++  int len = strlen(out);
++  if (len && out[len-1]=='\n')
++    out[len-1] = 0;
++
++  fclose(fp);
++
++  *rstr = strdup(out);
++}
++
++void get_hime_conf_fstr(char *name, char rstr[], char *default_str)
++{
++  char *tt = NULL;
++  get_hime_conf_str(name, &tt, default_str);
++  strcpy(rstr, tt);
++  free(tt);
++}
++
++int get_hime_conf_int(char *name, int default_value)
++{
++  char tt[32];
++  char default_value_str[MAX_HIME_STR];
++
++  sprintf(default_value_str, "%d", default_value);
++  get_hime_conf_fstr(name, tt, default_value_str);
++
++  return atoi(tt);
++}
++
++
++void save_hime_conf_str(char *name, char *str)
++{
++  FILE *fp;
++  char fname[256];
++
++  g_key_file_set_value(hime_omni_config, "HIME", name, str);
++
++  /* Compatible for previous configuration */
++  get_hime_conf_fname(name, fname);
++
++  if ((fp=fopen(fname,"wb"))==NULL) {
++    p_err("cannot create %s", fname);
++  }
++
++  fprintf(fp, "%s", str);
++  fclose(fp);
++}
++
++
++void save_hime_conf_int(char *name, int val)
++{
++  char tt[16];
++
++  sprintf(tt, "%d", val);
++  save_hime_conf_str(name, tt);
++}
++
++void get_sys_table_file_name(char *name, char *fname)
++{
++  sprintf(fname, "%s/%s", TableDir, name);
++}
++#endif /* !CLIENT_LIB */
++
++char *get_hime_xim_name()
++{
++  char *xim_name;
++
++  if ((xim_name=getenv("XMODIFIERS"))) {
++    static char find[] = "@im=";
++    static char sstr[32];
++    char *p = strstr(xim_name, find);
++
++    if (p==NULL) return "hime";
++
++    p += strlen(find);
++    strncpy(sstr, p, sizeof(sstr));
++    sstr[sizeof(sstr) - 1]=0;
++
++    if ((p=strchr(sstr, '.')))
++      *p=0;
++
++//    dbg("Try to use name from XMODIFIERS=@im=%s\n", sstr);
++    return sstr;
++  }
++
++  return "hime";
++}
++
++Atom get_hime_atom(Display *dpy)
++{
++  char *xim_name = get_hime_xim_name();
++  char tt[128];
++
++  snprintf(tt, sizeof(tt), "HIME_ATOM_%s", xim_name);
++
++  Atom atom = XInternAtom(dpy, tt, False);
++
++  return atom;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime-conf.h b/src/plugins/platforminputcontexts/hime/include/hime-conf.h
+new file mode 100644
+index 0000000..4ef79f1
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime-conf.h
+@@ -0,0 +1,159 @@
++#define CHANGE_FONT_SIZE "change font size"
++#define GB_OUTPUT_TOGGLE "gb output toggle"
++#define SIM_OUTPUT_TOGGLE "gb output sim"
++#define TRAD_OUTPUT_TOGGLE "gb output trad"
++#define KBM_TOGGLE "kbm toggle"
++#define UPDATE_TRAY "update tray"
++#define RELOAD_TSIN_DB "reload tsin db"
++#define HIME_EXIT_MESSAGE "hime exit"
++
++
++#define HIME_SETUP_WINDOW_TYPE_UTILITY "hime-setup-window-type-utility"
++#define HIME_FONT_SIZE "hime-font-size"
++#define HIME_FONT_NAME "hime-font-name"
++#define HIME_FONT_SIZE_TSIN_PRESEL "hime-font-size-tsin-presel"
++#define HIME_FONT_SIZE_SYMBOL "hime-font-size-symbol"
++#define HIME_FONT_SIZE_TSIN_PHO_IN "hime-font-size-tsin-pho-in"
++#define HIME_FONT_SIZE_GTAB_IN "hime-font-size-gtab-in"
++#define HIME_FONT_SIZE_PHO_NEAR "hime-font-size-pho-near"
++#define HIME_FONT_SIZE_WIN_KBM "hime-font-size-win-kbm"
++#define HIME_FONT_SIZE_WIN_KBM_EN "hime-font-size-win-kbm-en"
++#define HIME_INPUT_STYLE "hime-input-style"
++#define HIME_ROOT_X      "hime-root-x"
++#define HIME_ROOT_Y      "hime-root-y"
++#define HIME_POP_UP_WIN "hime-pop-up-win"
++#define HIME_ICON_DIR "hime-icon-dir"
++#define HIME_INNER_FRAME "hime-inner-frame"
++#define HIME_INIT_IM_ENABLED "hime-init-im-enabled"
++#define HIME_INIT_FULL_MODE "hime-init-full-mode"
++#define HIME_BELL_VOLUME "hime-bell-volume"
++#define HIME_SOUND_PLAY_OVERLAP "hime-sound-play-overlap"
++#define HIME_ENABLE_CTRL_ALT_SWITCH "hime-enable-ctrl-alt-switch"
++#define HIME_EDIT_DISPLAY "hime-edit-display"
++#define HIME_BELL_OFF "hime-bell-off"
++#define HIME_ON_THE_SPOT_KEY "hime-on-the-spot-key"
++#define HIME_TRAY_HF_WIN_KBM "hime-tray-hf-win-kbm"
++#define HIME_SINGLE_STATE "hime-single-state"
++#define HIME_PUNC_AUTO_SEND "hime-punc-auto-send"
++
++#define HIME_IM_TOGGLE_KEYS "hime-im-toggle-keys"
++#define DEFAULT_INPUT_METHOD "default-input-method"
++// #define LEFT_RIGHT_BUTTON_TIPS "left-right-button-tips"
++#define HIME_STR_IM_CYCLE "hime-str-im-cycle"
++#define HIME_REMOTE_CLIENT "hime-remote-client"
++#define HIME_SHIFT_SPACE_ENG_FULL "hime-shift-space-eng-full"
++#define HIME_STATUS_TRAY "hime-status-tray"
++#define HIME_WIN_COLOR_FG "hime-win-color-fg"
++#define HIME_WIN_COLOR_BG "hime-win-color-bg"
++#define HIME_WIN_COLOR_USE "hime-win-color-use"
++#define HIME_CAPSLOCK_LOWER "hime-capslock-lower"
++#define HIME_ENG_PHRASE_ENABLED "hime-eng-phrase-enabled"
++#define HIME_WIN_SYM_CLICK_CLOSE "hime-win-sym-click-close"
++#define HIME_SEL_KEY_COLOR "hime-sel-key-color"
++#define HIME_TRAY_DISPLAY "hime-tray-display"
++
++#define GTAB_DUP_SELECT_BELL "gtab-dup-select-bell"
++#define GTAB_SPACE_AUTO_FIRST "gtab-space-auto-first"
++#define GTAB_AUTO_SELECT_BY_PHRASE "gtab-auto-select-by_phrase"
++#define GTAB_PRE_SELECT "gtab-pre-select"
++#define GTAB_PHRASE_PRE_SELECT "gtab-phrase-pre-select"
++#define GTAB_PRESS_FULL_AUTO_SEND "gtab-press-full-auto-send"
++#define GTAB_DISP_PARTIAL_MATCH "gtab-disp-partial-match"
++#define GTAB_DISP_KEY_CODES "gtab-disp-key-codes"
++#define GTAB_DISP_IM_NAME "gtab-disp-im-name"
++#define GTAB_INVALID_KEY_IN "gtab-invalid-key-in"
++#define GTAB_SHIFT_PHRASE_KEY "gtab-shift-phrase-key"
++#define GTAB_HIDE_ROW2 "gtab-hide-row2"
++#define GTAB_IN_ROW1 "gtab-in-row1"
++#define GTAB_VERTICAL_SELECT "gtab-vertical-select"
++#define GTAB_UNIQUE_AUTO_SEND "gtab-unique-auto-send"
++#define GTAB_QUE_WILD_CARD "gtab-que-wild-card"
++#define GTAB_QUE_WILD_CARD_ASTERISK "gtab-que-wild-card-asterisk"
++#define GTAB_PHO_QUERY "gtab-pho-query"
++#define GTAB_PHRASE_PRE_SELECT "gtab-phrase-pre-select"
++#define GTAB_IN_AREA_BUTTON "gtab-in-area-button"
++
++
++#define TSIN_PHRASE_PRE_SELECT "tsin-phrase-pre-select"
++#define TSIN_CHINESE_ENGLISH_TOGGLE_KEY "tsin-chinese-english-toggle_key"
++#define TSIN_SPACE_OPT "tsin-space-opt"
++#define TSIN_BUFFER_SIZE "tsin-buffer-size"
++#define TSIN_PHRASE_LINE_COLOR "tsin-phrase-line-color"
++#define TSIN_CURSOR_COLOR "tsin-cursor-color"
++#define TSIN_TONE_CHAR_INPUT "tsin-tone-char-input"
++#define TSIN_TAB_PHRASE_END "tsin-tab-phrase-end"
++#define TSIN_TAIL_SELECT_KEY "tsin-tail-select-key"
++#define TSIN_BUFFER_EDITING_MODE "tsin-buffer-editing-mode"
++#define TSIN_USE_PHO_NEAR "tsin-use-pho-near"
++
++#define PHO_HIDE_ROW2 "pho-hide-row2"
++#define PHO_IN_ROW1 "pho-in-row1"
++
++
++#define PHONETIC_KEYBOARD "phonetic-keyboard2"
++#define PHONETIC_KEYBOARD_BAK "phonetic-keyboard-bak"
++
++#define PHONETIC_CHAR_DYNAMIC_SEQUENCE "phonetic-char-dynamic-sequence"
++#define PHONETIC_HUGE_TAB "phonetic-huge-tab"
++#define PHONETIC_SPEAK "phonetic-speak"
++#define PHONETIC_SPEAK_SEL "phonetic-speak-sel"
++
++extern int hime_setup_window_type_utility,
++           hime_font_size, hime_font_size_tsin_presel, hime_font_size_symbol,
++           hime_font_size_tsin_pho_in, hime_font_size_pho_near,
++           hime_font_size_gtab_in, hime_font_size_win_kbm, hime_font_size_win_kbm_en,
++           hime_inner_frame, hime_single_state,
++           hime_remote_client,
++           gtab_disp_key_codes, gtab_disp_im_name, hime_shift_space_eng_full,
++           gtab_invalid_key_in, gtab_hide_row2, gtab_in_row1,
++           hime_capslock_lower, pho_hide_row2, pho_in_row1,
++           hime_eng_phrase_enabled, hime_win_sym_click_close,
++           gtab_que_wild_card, gtab_que_wild_card_asterisk, gtab_pho_query,
++           hime_bell_volume, hime_sound_play_overlap, hime_enable_ctrl_alt_switch, hime_on_the_spot_key;
++
++extern int default_input_method;
++// extern int left_right_button_tips;
++extern int gtab_dup_select_bell;
++extern int gtab_space_auto_first;
++extern int gtab_auto_select_by_phrase;
++extern int hime_im_toggle_keys;
++extern int gtab_pre_select, gtab_phrase_pre_select;
++extern int gtab_press_full_auto_send;
++extern int gtab_disp_partial_match;
++extern int gtab_shift_phrase_key, gtab_in_area_button;
++extern int gtab_vertical_select, gtab_unique_auto_send;
++extern int tsin_buffer_size;
++extern int hime_input_style, hime_root_x, hime_root_y, hime_pop_up_win;
++extern int hime_status_tray, hime_show_win_kbm, hime_tray_hf_win_kbm;
++extern int hime_punc_auto_send;
++
++extern int tsin_phrase_pre_select;
++extern int tsin_chinese_english_toggle_key;
++extern int tsin_tab_phrase_end, tsin_tail_select_key;
++extern int tsin_buffer_editing_mode;
++extern int tsin_use_pho_near;
++
++extern int phonetic_char_dynamic_sequence;
++extern int phonetic_huge_tab, phonetic_speak;
++extern char *phonetic_speak_sel;
++extern int tsin_space_opt, tsin_tone_char_input;
++
++extern char *tsin_phrase_line_color, *tsin_cursor_color, *hime_font_name, *hime_sel_key_color, *hime_icon_dir;
++extern unich_t eng_full_str[], eng_half_str[], cht_full_str[];
++extern char *eng_color_full_str, *eng_color_half_str, *cht_color_full_str;
++extern char *hime_win_color_fg, *hime_win_color_bg;
++extern int hime_win_color_use, hime_bell_off;
++extern int hime_init_im_enabled, hime_init_full_mode;
++extern int hime_edit_display, hime_tray_display;
++extern char *pho_kbm_name, *pho_selkey, *hime_str_im_cycle;
++extern int pho_candicate_col_N, pho_candicate_R2L;
++
++gboolean get_hime_user_fname(char *name, char fname[]);
++void get_hime_conf_str(char *name, char **rstr, char *default_str);
++void get_hime_conf_fstr(char *name, char rstr[], char *default_str);
++void save_hime_conf_str(char *name, char *str);
++void save_hime_conf_int(char *name, int val);
++void load_settings();
++void save_omni_config(void);
++void free_omni_config(void);
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime-crypt.c b/src/plugins/platforminputcontexts/hime/include/hime-crypt.c
+new file mode 100644
+index 0000000..f35b4f4
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime-crypt.c
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2009 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "im-client/hime-protocol.h"
++
++static int __hime_rand__(u_int *next)
++{
++  *next = *next * 1103515245 + 12345;
++  return((unsigned)(*next/65536) % 32768);
++}
++
++void __hime_enc_mem(u_char *p, int n,
++                    HIME_PASSWD *passwd, u_int *seed)
++{
++  int i;
++
++  for(i=0; i < n; i++) {
++    int v = __hime_rand__(seed) % __HIME_PASSWD_N_;
++    p[i]^=passwd->passwd[v];
++  }
++}
++
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime-endian.h b/src/plugins/platforminputcontexts/hime/include/hime-endian.h
+new file mode 100644
+index 0000000..fe5970e
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime-endian.h
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2009 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#define swap_ch(a, b) do { char t; t = *(a); *(a) = *(b); *(b) = t; } while (0)
++
++#define swap_byte_2(pp) do { char *p=(char *)pp;  swap_ch(p, p+1); } while (0)
++#define swap_byte_4(pp) do { char *p=(char *)pp;  swap_ch(p, p+3); swap_ch(p+1, p+2); } while (0)
++#define swap_byte_8(pp) do { char *p=(char *)pp;  swap_ch(p, p+7); swap_ch(p+1, p+6); swap_ch(p+2, p+5); swap_ch(p+3, p+4);} while (0)
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++//#warning "big endian"
++#define to_hime_endian_2(pp) swap_byte_2(pp)
++#define to_hime_endian_4(pp) swap_byte_4(pp)
++#define to_hime_endian_8(pp) swap_byte_8(pp)
++#else
++#define to_hime_endian_2(pp) do { } while (0)
++#define to_hime_endian_4(pp) do { } while (0)
++#define to_hime_endian_8(pp) do { } while (0)
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime-gtk-compatible.h b/src/plugins/platforminputcontexts/hime/include/hime-gtk-compatible.h
+new file mode 100644
+index 0000000..cc4ea9c
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime-gtk-compatible.h
+@@ -0,0 +1,139 @@
++#if !GTK_CHECK_VERSION(2,13,4)
++#define gtk_widget_get_window(x) (x)->window
++#define gtk_color_selection_dialog_get_color_selection(x) (x)->colorsel
++#endif
++
++#if !GTK_CHECK_VERSION(2,15,0)
++#define gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip
++#endif
++
++#if !GTK_CHECK_VERSION(2,16,0)
++#include <X11/XKBlib.h>
++#include <gdk/gdkx.h>
++#define gdk_keymap_get_caps_lock_state(x) get_caps_lock_state()
++#endif
++
++#if GTK_CHECK_VERSION(2,17,5)
++#undef GTK_WIDGET_NO_WINDOW
++#define GTK_WIDGET_NO_WINDOW !gtk_widget_get_has_window
++#undef GTK_WIDGET_SET_FLAGS
++#define GTK_WIDGET_SET_FLAGS(x,y) gtk_widget_set_can_default(x,1)
++#endif
++
++#if GTK_CHECK_VERSION(2,17,7)
++#undef GTK_WIDGET_VISIBLE
++#define GTK_WIDGET_VISIBLE gtk_widget_get_visible
++#endif
++
++#if GTK_CHECK_VERSION(2,17,10)
++#undef GTK_WIDGET_DRAWABLE
++#define GTK_WIDGET_DRAWABLE gtk_widget_is_drawable
++#endif
++
++#if GTK_CHECK_VERSION(2,19,5)
++#undef GTK_WIDGET_REALIZED
++#define GTK_WIDGET_REALIZED gtk_widget_get_realized
++#endif
++
++#if GTK_CHECK_VERSION(2,21,8)
++#undef GDK_DISPLAY
++#define GDK_DISPLAY() GDK_DISPLAY_XDISPLAY(gdk_display_get_default())
++#endif
++
++#if GTK_CHECK_VERSION(2,24,0)
++#define gdk_window_lookup_for_display gdk_x11_window_lookup_for_display
++#define gtk_combo_box_new_text gtk_combo_box_text_new
++#define gtk_combo_box_append_text gtk_combo_box_text_append_text
++#define gtk_widget_hide_all gtk_widget_hide
++#endif
++
++#if GTK_CHECK_VERSION(2,90,0)
++#undef GTK_CHECK_CAST
++#define GTK_CHECK_CAST G_TYPE_CHECK_INSTANCE_CAST
++#undef GDK_DRAWABLE_XID
++#define GDK_DRAWABLE_XID GDK_WINDOW_XID
++#undef GDK_DRAWABLE_XDISPLAY
++#define GDK_DRAWABLE_XDISPLAY GDK_WINDOW_XDISPLAY
++#define gtk_hseparator_new() gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
++#define gtk_vseparator_new() gtk_separator_new(GTK_ORIENTATION_VERTICAL)
++#endif
++
++#if !GTK_CHECK_VERSION(2,91,0)
++#define gdk_error_trap_pop_ignored gdk_error_trap_pop
++#define gtk_widget_get_preferred_size(x,y,z) gtk_widget_size_request(x,z)
++#define gtk_widget_set_halign(x,y);
++#endif
++
++#if GTK_CHECK_VERSION(2,91,0)
++#define GTK_OBJECT
++#define gdk_drawable_get_screen gdk_window_get_screen
++#endif
++
++#if !GTK_CHECK_VERSION(2,91,1)
++#define gtk_window_set_has_resize_grip(x,y);
++#define gtk_widget_set_hexpand(x,y);
++#define gtk_widget_set_vexpand(x,y);
++#endif
++
++#if !GTK_CHECK_VERSION(2,91,2)
++#define gtk_grid_set_column_homogeneous(x,y);
++#define gtk_grid_set_row_homogeneous(x,y);
++#define gtk_orientable_set_orientation(x,y);
++#endif
++
++#if GTK_CHECK_VERSION(2,91,2)
++#undef GTK_BOX
++#define GTK_BOX GTK_GRID
++#define gtk_hbox_new(x,y) gtk_grid_new()
++#define gtk_vbox_new(x,y) gtk_grid_new()
++#define gtk_box_pack_end(v,w,x,y,z) gtk_container_add(GTK_CONTAINER(v),w)
++#define gtk_box_pack_start(v,w,x,y,z) gtk_container_add(GTK_CONTAINER(v),w)
++#endif
++
++#ifndef GTK_COMBO_BOX_TEXT
++#define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX
++#endif
++
++#if !GTK_CHECK_VERSION(2,91,6)
++#define gtk_widget_override_font gtk_widget_modify_font
++#endif
++
++#if GTK_CHECK_VERSION(2,91,6)
++#define GDK_WINDOW_XWINDOW GDK_WINDOW_XID
++#endif
++
++#if GTK_CHECK_VERSION(3,3,2)
++#undef      GTK_TABLE
++#define     GTK_TABLE GTK_GRID
++#define     gtk_table_attach_defaults(u,v,w,x,y,z) gtk_grid_attach(u,v,w,y,1,1)
++#define     gtk_table_new(x,y,z) gtk_grid_new()
++#endif
++
++#if GTK_CHECK_VERSION(3,3,18)
++#define GTK_COLOR_SELECTION_DIALOG GTK_COLOR_CHOOSER_DIALOG
++#define GTK_COLOR_SELECTION GTK_COLOR_CHOOSER
++#endif
++
++#if GTK_CHECK_VERSION(3,9,8)
++#define gtk_image_menu_item_set_image(a,b) NULL
++#endif
++
++#if GTK_CHECK_VERSION(3,9,10)
++#define gtk_button_new_from_stock(x) gtk_button_new_from_icon_name(x,GTK_ICON_SIZE_BUTTON)
++#define GTK_STOCK_CANCEL "gtk-cancel"
++#define GTK_STOCK_OK "gtk-ok"
++#define GTK_STOCK_QUIT "gtk-quit"
++#define GTK_STOCK_SAVE "gtk-save"
++#define GTK_STOCK_OPEN "gtk-open"
++#define GTK_STOCK_CLOSE "gtk-close"
++#define GTK_STOCK_DELETE "gtk-delete"
++#define GTK_STOCK_FIND "gtk-find"
++#endif
++
++#if GTK_CHECK_VERSION(3,13,4)
++#define gtk_window_set_has_resize_grip(x,y);
++#endif
++
++#ifndef PANGO_VERSION_CHECK
++#define PANGO_VERSION_CHECK(x,y,z) FALSE
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime.c b/src/plugins/platforminputcontexts/hime/include/hime.c
+new file mode 100644
+index 0000000..1c17c59
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime.c
+@@ -0,0 +1,702 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "config.h"
++#include "gtab.h"
++#include <signal.h>
++#if HIME_i18n_message
++#include <libintl.h>
++#endif
++
++Window root;
++Display *dpy;
++
++int win_xl, win_yl;
++int win_x, win_y;   // actual win x/y
++int dpy_xl, dpy_yl;
++Window xim_xwin;
++
++extern unich_t *fullchar[];
++gboolean win_kbm_inited;
++char *get_hime_xim_name();
++
++char *half_char_to_full_char(KeySym xkey)
++{
++  if (xkey < ' ' || xkey > 127)
++    return NULL;
++  return _(fullchar[xkey-' ']);
++}
++
++static void start_inmd_window()
++{
++  GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++  gtk_widget_realize (win);
++  xim_xwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(win));
++  dbg("xim_xwin %x\n", xim_xwin);
++}
++
++#if USE_XIM
++char *lc;
++
++static XIMStyle Styles[] = {
++#if 1
++        XIMPreeditCallbacks|XIMStatusCallbacks,         //OnTheSpot
++        XIMPreeditCallbacks|XIMStatusArea,              //OnTheSpot
++        XIMPreeditCallbacks|XIMStatusNothing,           //OnTheSpot
++#endif
++        XIMPreeditPosition|XIMStatusArea,               //OverTheSpot
++        XIMPreeditPosition|XIMStatusNothing,            //OverTheSpot
++        XIMPreeditPosition|XIMStatusNone,               //OverTheSpot
++#if 1
++        XIMPreeditArea|XIMStatusArea,                   //OffTheSpot
++        XIMPreeditArea|XIMStatusNothing,                //OffTheSpot
++        XIMPreeditArea|XIMStatusNone,                   //OffTheSpot
++#endif
++        XIMPreeditNothing|XIMStatusNothing,             //Root
++        XIMPreeditNothing|XIMStatusNone,                //Root
++};
++static XIMStyles im_styles;
++
++#if 1
++static XIMTriggerKey trigger_keys[] = {
++        {XK_space, ControlMask, ControlMask},
++        {XK_space, ShiftMask, ShiftMask},
++        {XK_space, Mod1Mask, Mod1Mask},   // Alt
++        {XK_space, Mod4Mask, Mod4Mask},   // Windows
++};
++#endif
++
++/* Supported Encodings */
++static XIMEncoding chEncodings[] = {
++        "COMPOUND_TEXT",
++        0
++};
++static XIMEncodings encodings;
++
++int xim_ForwardEventHandler(IMForwardEventStruct *call_data);
++
++XIMS current_ims;
++extern void toggle_im_enabled();
++
++
++int MyTriggerNotifyHandler(IMTriggerNotifyStruct *call_data)
++{
++//    dbg("MyTriggerNotifyHandler %d %x\n", call_data->key_index, call_data->event_mask);
++
++    if (call_data->flag == 0) { /* on key */
++//        db(g("trigger %d\n", call_data->key_index);
++        if ((call_data->key_index == 0 && hime_im_toggle_keys==Control_Space) ||
++            (call_data->key_index == 3 && hime_im_toggle_keys==Shift_Space) ||
++            (call_data->key_index == 6 && hime_im_toggle_keys==Alt_Space) ||
++            (call_data->key_index == 9 && hime_im_toggle_keys==Windows_Space)
++            ) {
++            toggle_im_enabled();
++        }
++        return True;
++    } else {
++        /* never happens */
++        return False;
++    }
++}
++
++#if 0
++void switch_IC_index(int index);
++#endif
++void CreateIC(IMChangeICStruct *call_data);
++void DeleteIC(CARD16 icid);
++void SetIC(IMChangeICStruct * call_data);
++void GetIC(IMChangeICStruct *call_data);
++int xim_hime_FocusIn(IMChangeFocusStruct *call_data);
++int xim_hime_FocusOut(IMChangeFocusStruct *call_data);
++
++int hime_ProtoHandler(XIMS ims, IMProtocol *call_data)
++{
++//  dbg("hime_ProtoHandler %x ims\n", ims);
++
++  current_ims = ims;
++
++  switch (call_data->major_code) {
++  case XIM_OPEN:
++#define MAX_CONNECT 20000
++    {
++      IMOpenStruct *pimopen=(IMOpenStruct *)call_data;
++
++      if (pimopen->connect_id > MAX_CONNECT - 1)
++        return True;
++
++#if DEBUG && 0
++    dbg("open lang %s  connectid:%d\n", pimopen->lang.name, pimopen->connect_id);
++#endif
++      return True;
++    }
++  case XIM_CLOSE:
++#if DEBUG && 0
++    dbg("XIM_CLOSE\n");
++#endif
++    return True;
++  case XIM_CREATE_IC:
++#if DEBUG && 0
++     dbg("CREATE_IC\n");
++#endif
++     CreateIC((IMChangeICStruct *)call_data);
++     return True;
++  case XIM_DESTROY_IC:
++     {
++       IMChangeICStruct *pimcha=(IMChangeICStruct *)call_data;
++#if DEBUG && 0
++       dbg("DESTROY_IC %d\n", pimcha->icid);
++#endif
++       DeleteIC(pimcha->icid);
++     }
++     return True;
++  case XIM_SET_IC_VALUES:
++#if DEBUG && 0
++     dbg("SET_IC\n");
++#endif
++     SetIC((IMChangeICStruct *)call_data);
++     return True;
++  case XIM_GET_IC_VALUES:
++#if DEBUG && 0
++     dbg("GET_IC\n");
++#endif
++     GetIC((IMChangeICStruct *)call_data);
++     return True;
++  case XIM_FORWARD_EVENT:
++#if DEBUG && 0
++     dbg("XIM_FORWARD_EVENT\n");
++#endif
++     return xim_ForwardEventHandler((IMForwardEventStruct *)call_data);
++  case XIM_SET_IC_FOCUS:
++#if DEBUG && 0
++     dbg("XIM_SET_IC_FOCUS\n");
++#endif
++     return xim_hime_FocusIn((IMChangeFocusStruct *)call_data);
++  case XIM_UNSET_IC_FOCUS:
++#if DEBUG && 0
++     dbg("XIM_UNSET_IC_FOCUS\n");
++#endif
++     return xim_hime_FocusOut((IMChangeFocusStruct *)call_data);
++  case XIM_RESET_IC:
++#if DEBUG && 0
++     dbg("XIM_UNSET_IC_FOCUS\n");
++#endif
++     return True;
++  case XIM_TRIGGER_NOTIFY:
++#if DEBUG && 0
++     dbg("XIM_TRIGGER_NOTIFY\n");
++#endif
++     MyTriggerNotifyHandler((IMTriggerNotifyStruct *)call_data);
++     return True;
++  case XIM_PREEDIT_START_REPLY:
++#if DEBUG && 1
++     dbg("XIM_PREEDIT_START_REPLY\n");
++#endif
++     return True;
++  case XIM_PREEDIT_CARET_REPLY:
++#if DEBUG && 1
++     dbg("XIM_PREEDIT_CARET_REPLY\n");
++#endif
++     return True;
++  case XIM_STR_CONVERSION_REPLY:
++#if DEBUG && 1
++     dbg("XIM_STR_CONVERSION_REPLY\n");
++#endif
++     return True;
++  default:
++     printf("Unknown major code.\n");
++     break;
++  }
++
++  return True;
++}
++
++
++void open_xim()
++{
++  XIMTriggerKeys triggerKeys;
++
++  im_styles.supported_styles = Styles;
++  im_styles.count_styles = sizeof(Styles)/sizeof(Styles[0]);
++
++  triggerKeys.count_keys = sizeof(trigger_keys)/sizeof(trigger_keys[0]);
++  triggerKeys.keylist = trigger_keys;
++
++  encodings.count_encodings = sizeof(chEncodings)/sizeof(XIMEncoding) - 1;
++  encodings.supported_encodings = chEncodings;
++
++  char *xim_name = get_hime_xim_name();
++
++  XIMS xims = IMOpenIM(dpy,
++          IMServerWindow,         xim_xwin,        //input window
++          IMModifiers,            "Xi18n",        //X11R6 protocol
++          IMServerName,           xim_name, //XIM server name
++          IMLocale,               lc,
++          IMServerTransport,      "X/",      //Comm. protocol
++          IMInputStyles,          &im_styles,   //faked styles
++          IMEncodingList,         &encodings,
++          IMProtocolHandler,      hime_ProtoHandler,
++          IMFilterEventMask,      KeyPressMask|KeyReleaseMask,
++          IMOnKeysList, &triggerKeys,
++          NULL);
++
++  if (xims == NULL) {
++          p_err("IMOpenIM '%s' failed. Maybe another XIM server is running.\n",
++          xim_name);
++  }
++}
++
++#endif // if USE_XIM
++
++void load_tsin_db();
++void load_tsin_conf(), load_settings(), load_tab_pho_file();
++
++void disp_hide_tsin_status_row(), update_win_kbm_inited();
++void change_tsin_line_color(), change_win0_style(), change_tsin_color();
++void change_win_gtab_style();
++#if TRAY_ENABLED
++void update_item_active_all();
++#endif
++void destroy_inmd_menu();
++void load_gtab_list(gboolean);
++void change_win1_font();
++void set_wselkey(char *s);
++void create_win_gtab();
++
++#if TRAY_ENABLED
++void disp_tray_icon();
++#endif
++gboolean init_in_method(int in_no);
++#include "im-client/hime-protocol.h"
++#include "im-srv.h"
++
++static int get_in_method_by_filename(char filename[])
++{
++    int i, in_method = 0;
++    gboolean found = FALSE;
++    for(i=0; i < inmdN; i++) {
++      if (strcmp(filename, inmd[i].filename))
++        continue;
++      found = TRUE;
++      in_method = i;
++      break;
++    }
++    if (!found)
++      in_method = default_input_method;
++    return in_method;
++}
++
++static void reload_data()
++{
++  dbg("reload_data\n");
++//  Save input method state before reload
++  char temp_inmd_filenames[hime_clientsN][128];
++  HIME_STATE_E temp_CS_im_states[hime_clientsN];
++  char temp_current_CS_inmd_filename[128] = "";
++  HIME_STATE_E temp_current_CS_im_state = 0;
++  if (current_CS) {
++    temp_current_CS_im_state = current_CS->im_state;
++    strcpy(temp_current_CS_inmd_filename, inmd[current_CS->in_method].filename);
++  }
++  int c;
++  for(c=0;c<hime_clientsN;c++) {
++    strcpy(temp_inmd_filenames[c], "");
++    temp_CS_im_states[c] = HIME_STATE_DISABLED;
++    if (!hime_clients[c].cs)
++      continue;
++    ClientState *cs = hime_clients[c].cs;
++    temp_CS_im_states[c] = cs->im_state;
++    strcpy(temp_inmd_filenames[c], inmd[cs->in_method].filename);
++  }
++  free_omni_config();
++  load_settings();
++  if (current_method_type()==method_type_TSIN)
++    set_wselkey(pho_selkey);
++
++//  load_tsin_db();
++  change_win0_style();
++  change_win1_font();
++  create_win_gtab();
++  change_win_gtab_style();
++//  change_win_pho_style();
++  load_tab_pho_file();
++  change_tsin_color();
++  update_win_kbm_inited();
++
++  destroy_inmd_menu();
++  load_gtab_list(TRUE);
++
++#if TRAY_ENABLED
++  update_item_active_all();
++#endif
++
++//  Load input method state after reload, which may change inmd
++  // load clientstate properties back
++  for(c=0;c<hime_clientsN;c++) {
++    if (!hime_clients[c].cs)
++      continue;
++    hime_clients[c].cs->im_state = HIME_STATE_CHINESE;
++    hime_clients[c].cs->in_method = get_in_method_by_filename(temp_inmd_filenames[c]);
++    init_in_method(hime_clients[c].cs->in_method);
++    if (temp_CS_im_states[c] == HIME_STATE_DISABLED)
++      toggle_im_enabled();
++    hime_clients[c].cs->im_state = temp_CS_im_states[c];
++  }
++  current_CS->im_state = HIME_STATE_CHINESE;
++  init_in_method(get_in_method_by_filename(temp_current_CS_inmd_filename));
++  if (temp_current_CS_im_state == HIME_STATE_DISABLED)
++    toggle_im_enabled();
++  current_CS->im_state = temp_current_CS_im_state;
++}
++
++void change_tsin_font_size();
++void change_gtab_font_size();
++void change_pho_font_size();
++void change_win_sym_font_size();
++void change_win_gtab_style();
++extern gboolean win_kbm_on;
++extern void change_module_font_size();
++
++static void change_font_size()
++{
++  load_settings();
++  change_tsin_font_size();
++  change_gtab_font_size();
++  change_pho_font_size();
++  change_win_sym_font_size();
++  change_win0_style();
++  change_win_gtab_style();
++  update_win_kbm_inited();
++  change_win1_font();
++//  change_win_pho_style();
++  change_module_font_size();
++}
++
++static int xerror_handler(Display *d, XErrorEvent *eve)
++{
++  return 0;
++}
++
++Atom hime_atom;
++
++void toggle_gb_output();
++
++void cb_trad_sim_toggle()
++{
++  toggle_gb_output();
++#if TRAY_ENABLED
++  disp_tray_icon();
++#endif
++}
++void execute_message(char *message), show_win_kbm(), hide_win_kbm();
++void disp_win_kbm_capslock_init();
++
++extern int hime_show_win_kbm;
++void kbm_open_close(GtkButton *checkmenuitem, gboolean b_show)
++{
++  hime_show_win_kbm=b_show;
++
++  if (hime_show_win_kbm) {
++    show_win_kbm();
++    disp_win_kbm_capslock_init();
++  } else
++    hide_win_kbm();
++}
++
++void kbm_toggle()
++{
++  win_kbm_inited = 1;
++  kbm_open_close(NULL, ! hime_show_win_kbm);
++}
++
++
++void reload_tsin_db();
++void do_exit();
++
++void message_cb(char *message)
++{
++   void sim_output();  // FIXME
++   void trad_output(); // FIXME
++//   dbg("message '%s'\n", message);
++
++   /* TODO: rewrite the mess with case() ? */
++   if (!strcmp(message, CHANGE_FONT_SIZE)) {
++     change_font_size();
++   } else
++   if (!strcmp(message, GB_OUTPUT_TOGGLE)) {
++     cb_trad_sim_toggle();
++#if TRAY_ENABLED
++     update_item_active_all();
++#endif
++   } else
++   if (!strcmp(message, SIM_OUTPUT_TOGGLE)) {
++     sim_output();
++#if TRAY_ENABLED
++     disp_tray_icon();
++     update_item_active_all();
++#endif
++   } else
++   if (!strcmp(message, TRAD_OUTPUT_TOGGLE)) {
++     trad_output();
++#if TRAY_ENABLED
++     disp_tray_icon();
++     update_item_active_all();
++#endif
++   } else
++   if (!strcmp(message, KBM_TOGGLE)) {
++     kbm_toggle();
++   } else
++   if (strstr(message, "#hime_message")) {
++     execute_message(message);
++   } else
++#if TRAY_ENABLED
++   if (!strcmp(message, UPDATE_TRAY)) {
++     disp_tray_icon();
++   } else
++#endif
++   if (!strcmp(message, RELOAD_TSIN_DB)) {
++     reload_tsin_db();
++   } else
++   if (!strcmp(message, HIME_EXIT_MESSAGE)) {
++     do_exit();
++   } else
++     reload_data();
++}
++
++static GdkFilterReturn my_gdk_filter(GdkXEvent *xevent,
++                                     GdkEvent *event,
++                                     gpointer data)
++{
++   XEvent *xeve = (XEvent *)xevent;
++#if 0
++   dbg("a zzz %d\n", xeve->type);
++#endif
++
++   // only very old WM will enter this
++   if (xeve->type == FocusIn || xeve->type == FocusOut) {
++#if 0
++     dbg("focus %s\n", xeve->type == FocusIn ? "in":"out");
++#endif
++     return GDK_FILTER_REMOVE;
++   }
++
++#if USE_XIM
++   if (XFilterEvent(xeve, None) == True)
++     return GDK_FILTER_REMOVE;
++#endif
++
++   return GDK_FILTER_CONTINUE;
++}
++
++void init_atom_property()
++{
++  hime_atom = get_hime_atom(dpy);
++  XSetSelectionOwner(dpy, hime_atom, xim_xwin, CurrentTime);
++}
++
++void hide_win0();
++void destroy_win0();
++void destroy_win1();
++void destroy_win_gtab();
++void free_pho_mem(),free_tsin(),free_all_IC(), free_gtab(), free_phrase();
++#if TRAY_ENABLED
++void destroy_tray();
++#endif
++
++void do_exit()
++{
++  dbg("----------------- do_ exit ----------------\n");
++
++  free_pho_mem();
++  free_tsin();
++#if USE_XIM
++  free_all_IC();
++#endif
++  free_gtab();
++  free_phrase();
++
++#if 1
++  destroy_win0();
++  destroy_win1();
++  destroy_win_gtab();
++#endif
++
++#if TRAY_ENABLED
++  destroy_tray();
++#endif
++
++  free_omni_config();
++  gtk_main_quit();
++}
++
++void sig_do_exit(int sig)
++{
++  do_exit();
++}
++
++void load_phrase(), init_TableDir();
++void init_tray(), exec_setup_scripts();
++void init_hime_im_serv(Window win);
++void init_tray_double();
++
++#if TRAY_UNITY
++void init_tray_appindicator();
++#endif
++
++gboolean delayed_start_cb(gpointer data)
++{
++#if TRAY_ENABLED
++  if (hime_status_tray) {
++    if (hime_tray_display == HIME_TRAY_DISPLAY_SINGLE)
++      init_tray();
++    else if (hime_tray_display == HIME_TRAY_DISPLAY_DOUBLE)
++      init_tray_double();
++#if TRAY_UNITY
++    else if (hime_tray_display == HIME_TRAY_DISPLAY_APPINDICATOR)
++      init_tray_appindicator();
++#endif
++  }
++#endif
++
++  dbg("after init_tray\n");
++
++  return FALSE;
++}
++
++void get_dpy_xyl()
++{
++	dpy_xl = gdk_screen_width(), dpy_yl = gdk_screen_height();
++}
++
++void screen_size_changed(GdkScreen *screen, gpointer user_data)
++{
++	get_dpy_xyl();
++}
++
++#include "lang.h"
++
++extern int destroy_window;
++
++int main(int argc, char **argv)
++{
++  char *destroy = getenv("HIME_DESTROY_WINDOW");
++  if (destroy)
++    destroy_window = atoi(destroy);
++//  printf("HIME_DESTROY_WINDOW=%d\n",destroy_window);
++
++  gtk_init (&argc, &argv);
++
++  signal(SIGCHLD, SIG_IGN);
++  signal(SIGPIPE, SIG_IGN);
++
++  if (getenv("HIME_DAEMON")) {
++    daemon(1,1);
++#if FREEBSD
++    setpgid(0, getpid());
++#else
++    setpgrp();
++#endif
++  }
++
++  set_is_chs();
++
++  char *lc_ctype = getenv("LC_CTYPE");
++  char *lc_all = getenv("LC_ALL");
++  char *lang = getenv("LANG");
++  if (!lc_ctype && lang)
++    lc_ctype = lang;
++
++  if (lc_all)
++    lc_ctype = lc_all;
++
++  if (!lc_ctype)
++    lc_ctype = "zh_TW.Big5";
++  dbg("hime get env LC_CTYPE=%s  LC_ALL=%s  LANG=%s\n", lc_ctype, lc_all, lang);
++
++#if USE_XIM
++  char *t = strchr(lc_ctype, '.');
++  if (t) {
++    int len = t - lc_ctype;
++#if MAC_OS || FREEBSD
++    lc = strdup(lc_ctype);
++    lc[len] = 0;
++#else
++    lc = g_strndup(lc_ctype, len);
++#endif
++  }
++  else
++    lc = lc_ctype;
++
++  dbg("hime XIM will use %s as the default encoding\n", lc_ctype);
++#endif
++
++  if (argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-h")) ) {
++#if GIT_HAVE
++    p_err(" version %s (git %s)\n", HIME_VERSION, GIT_HASH);
++#else
++    p_err(" version %s\n", HIME_VERSION);
++#endif
++  }
++
++  init_TableDir();
++  load_settings();
++  load_gtab_list(TRUE);
++
++
++#if HIME_i18n_message
++  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
++  textdomain(GETTEXT_PACKAGE);
++#endif
++
++  dbg("after gtk_init\n");
++
++  dpy = GDK_DISPLAY();
++  root=DefaultRootWindow(dpy);
++  get_dpy_xyl();
++  g_signal_connect(gdk_screen_get_default(),"size-changed", G_CALLBACK(screen_size_changed), NULL);
++
++  dbg("display width:%d height:%d\n", dpy_xl, dpy_yl);
++
++  start_inmd_window();
++
++#if USE_XIM
++  open_xim();
++#endif
++
++  gdk_window_add_filter(NULL, my_gdk_filter, NULL);
++
++  init_atom_property();
++  signal(SIGINT, sig_do_exit);
++  signal(SIGHUP, sig_do_exit);
++  // disable the io handler abort
++  // void *olderr =
++    XSetErrorHandler((XErrorHandler)xerror_handler);
++
++  init_hime_im_serv(xim_xwin);
++
++  exec_setup_scripts();
++
++  g_timeout_add(200, delayed_start_cb, NULL); // Old setting is 5000 here.
++
++  dbg("before gtk_main\n");
++
++  disp_win_kbm_capslock_init();
++
++  gtk_main();
++
++  return 0;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/hime.h b/src/plugins/platforminputcontexts/hime/include/hime.h
+new file mode 100644
+index 0000000..047cc12
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/hime.h
+@@ -0,0 +1,181 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include "os-dep.h"
++#include <gtk/gtk.h>
++#include <string.h>
++#include "IMdkit/include/IMdkit.h"
++#include "IMdkit/include/Xi18n.h"
++#if HIME_i18n_message
++#include <libintl.h>
++#define _(STRING) gettext(STRING)
++#else
++#define _(STRING) (STRING)
++#endif
++
++#define N_(STRING) (STRING)
++
++#include "hime-gtk-compatible.h"
++
++typedef enum {
++  HIME_STATE_DISABLED = 0,
++  HIME_STATE_ENG_FULL = 1,
++  HIME_STATE_CHINESE = 2
++} HIME_STATE_E;
++
++/* change 3 to 4 if you want to use 4-byte UTF-8 characters, but you must
++   regenerate *.gtab tsin
++*/
++#define CH_SZ (4)
++
++
++#include "IC.h"
++
++#if CLIENT_LIB
++#define p_err __hime_p_err
++#define zmalloc __hime_zmalloc
++#endif
++
++#include "util.h"
++
++#define tmalloc(type,n)  (type*)malloc(sizeof(type) * (n))
++void *zmalloc(int n);
++void *memdup(void *p, int n);
++#define tzmalloc(type,n)  (type*)zmalloc(sizeof(type) * (n))
++#define trealloc(p,type,n)  (type*)realloc(p, sizeof(type) * (n+1))
++#define tmemdup(p,type,n) (type*)memdup(p, sizeof(type) * n)
++extern Display *dpy;
++
++extern char *TableDir;
++extern GtkWidget *gwin0;
++extern GdkWindow *gdkwin0;
++extern Window xwin0;
++extern Window root;
++void loadIC();
++IC *FindIC(CARD16 icid);
++extern ClientState *current_CS;
++
++enum {
++  InputStyleOverSpot = 1,
++  InputStyleRoot = 2,
++  InputStyleOnSpot = 4
++};
++
++typedef enum {
++  Control_Space=0,
++  Shift_Space=1,
++  Alt_Space=2,
++  Windows_Space=3,
++} IM_TOGGLE_KEYS;
++
++enum {
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_None=0,
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_CapsLock=1,
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Tab=2,
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Shift=4,
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftL=8,
++  TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftR=16,
++};
++
++typedef enum {
++  TSIN_SPACE_OPT_SELECT_CHAR = 1,
++  TSIN_SPACE_OPT_INPUT = 2,
++} TSIN_SPACE_OPT;
++
++enum {
++  HIME_EDIT_DISPLAY_OVER_THE_SPOT=1,
++  HIME_EDIT_DISPLAY_ON_THE_SPOT=2,
++  HIME_EDIT_DISPLAY_BOTH=4,
++};
++
++#if TRAY_ENABLED
++enum {
++  HIME_TRAY_DISPLAY_SINGLE=1,
++  HIME_TRAY_DISPLAY_DOUBLE=2,
++  HIME_TRAY_DISPLAY_APPINDICATOR=3,
++};
++#endif
++
++#define HIME_SEL_KEY_COLOR_DEFAULT "blue"
++#define TSIN_CURSOR_COLOR_DEFAULT "blue"
++
++#define ROW_ROW_SPACING (2)
++
++
++#define MAX_HIME_STR (256)
++
++#define PHO_KBM "phokbm"
++
++extern int win_xl, win_yl;
++extern int win_x, win_y;   // actual win x/y
++extern int  current_in_win_x,  current_in_win_y;  // request x/y
++extern int dpy_xl, dpy_yl;
++
++extern int hime_font_size;
++
++void big5_utf8(char *s, char out[]);
++void utf8_big5(char *s, char out[]);
++gint inmd_switch_popup_handler (GtkWidget *widget, GdkEvent *event);
++
++#include "hime-conf.h"
++
++#define bchcpy(a,b) memcpy(a,b, CH_SZ)
++#define bchcmp(a,b) memcmp(a,b, CH_SZ)
++
++int utf8_sz(char *s);
++int utf8cpy(char *t, char *s);
++int u8cpy(char *t, char *s);
++int utf8_tlen(char *s, int N);
++void utf8_putchar(char *s);
++void utf8_putcharn(char *s, int n);
++gboolean utf8_eq(char *a, char *b);
++gboolean utf8_str_eq(char *a, char *b, int len);
++void utf8cpyN(char *t, char *s, int N);
++int utf8_str_N(char *str);
++void utf8cpyn(char *t, char *s, int n);
++void utf8cpy_bytes(char *t, char *s, int n);
++char *myfgets(char *buf, int bufN, FILE *fp);
++void get_hime_dir(char *tt);
++Atom get_hime_atom(Display *dpy);
++void get_sys_table_file_name(char *name, char *fname);
++char *half_char_to_full_char(KeySym xkey);
++void send_text(char *text);
++void send_utf8_ch(char *bchar);
++void send_ascii(char key);
++void bell();
++void set_label_font_size(GtkWidget *label, int size);
++void send_hime_message(Display *dpy, char *s);
++void check_CS();
++gint64 current_time();
++void get_win_size(GtkWidget *win, int *width, int *height);
++void change_win_fg_bg(GtkWidget *win, GtkWidget *label);
++void set_no_focus(GtkWidget *win);
++void change_win_bg(GtkWidget *win);
++gboolean hime_edit_display_ap_only();
++gboolean hime_display_on_the_spot_key();
++void char_play(char *utf8);
++void skip_utf8_sigature(FILE *fp);
++
++#define BITON(flag, bit) ((flag) & (bit))
++
++typedef int usecount_t;
++
++#define MAX_CIN_PHR (100*CH_SZ + 1)
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-addr.c b/src/plugins/platforminputcontexts/hime/include/im-addr.c
+new file mode 100644
+index 0000000..642b34a
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-addr.c
+@@ -0,0 +1,95 @@
++/* Copyright (C) 2009 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <pwd.h>
++#include <string.h>
++#include <dirent.h>
++#include <sys/stat.h>
++#include "hime.h"
++
++char *get_hime_xim_name();
++
++void get_hime_im_srv_sock_path(char *outstr, int outstrN)
++{
++  char *disp = getenv("DISPLAY");
++  int my_uid = getuid();
++
++  if (!disp || !strcmp(disp, ":0"))
++    disp = ":0.0";
++
++  char tdisp[64];
++  strcpy(tdisp, disp);
++
++  if (!strchr(disp, ':'))
++      strcat(tdisp, ":0");
++  if (!strchr(disp, '.'))
++      strcat(tdisp, ".0");
++
++  char my_dir[128];
++
++  struct passwd *pw = getpwuid(my_uid);
++  snprintf(my_dir, sizeof(my_dir), "%s/.hime-%s", g_get_tmp_dir(), pw->pw_name);
++  struct stat st;
++
++  if (stat(my_dir, &st) < 0)
++    mkdir(my_dir, 0700);
++  else {
++    if (st.st_uid != my_uid) {
++      fprintf(stderr, "please check the permission of dir %s\n", my_dir);
++      return;
++    }
++  }
++
++  snprintf(outstr,outstrN, "%s/socket-%s-%s", my_dir, tdisp, get_hime_xim_name());
++}
++
++
++Atom get_hime_addr_atom(Display *dpy)
++{
++  if (!dpy) {
++    dbg("dpy is null\n");
++    return 0;
++  }
++
++  char *xim_name = get_hime_xim_name();
++  char tt[128];
++
++  snprintf(tt, sizeof(tt), "HIME_ADDR_ATOM_%s", xim_name);
++
++  Atom atom = XInternAtom(dpy, tt, False);
++
++  return atom;
++}
++
++
++
++Atom get_hime_sockpath_atom(Display *dpy)
++{
++  if (!dpy) {
++    dbg("dpy is null\n");
++    return 0;
++  }
++
++  char *xim_name = get_hime_xim_name();
++  char tt[128];
++
++  snprintf(tt, sizeof(tt), "HIME_SOCKPATH_ATOM_%s", xim_name);
++
++  Atom atom = XInternAtom(dpy, tt, False);
++
++  return atom;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client-attr.h b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client-attr.h
+new file mode 100644
+index 0000000..ea7369c
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client-attr.h
+@@ -0,0 +1,9 @@
++#define HIME_PREEDIT_ATTR_FLAG_UNDERLINE 1
++#define HIME_PREEDIT_ATTR_FLAG_REVERSE 2
++#define HIME_PREEDIT_ATTR_MAX_N 64
++#define HIME_PREEDIT_MAX_STR 512
++
++typedef struct {
++  int flag;
++  short ofs0, ofs1;   // ofs : bytes offset
++} HIME_PREEDIT_ATTR;
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.c b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.c
+new file mode 100644
+index 0000000..fa67248
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.c
+@@ -0,0 +1,815 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include "../hime.h"
++#include "hime-protocol.h"
++#include "hime-im-client.h"
++#define DBG 0
++static int flags_backup;
++
++Atom get_hime_sockpath_atom(Display *dpy);
++static void save_old_sigaction_single(int signo, struct sigaction *act)
++{
++  sigaction(signo, NULL, act);
++
++  if (act->sa_handler != SIG_IGN) {
++    signal(signo, SIG_IGN);
++  }
++}
++
++static void restore_old_sigaction_single(int signo, struct sigaction *act)
++{
++  if (act->sa_handler != SIG_IGN)
++    signal(signo, act->sa_handler);
++}
++char *get_hime_im_srv_sock_path();
++Atom get_hime_addr_atom(Display *dpy);
++
++Window find_hime_window(Display *dpy)
++{
++  Atom hime_addr_atom = get_hime_addr_atom(dpy);
++  if (!hime_addr_atom)
++    return FALSE;
++  return XGetSelectionOwner(dpy, hime_addr_atom);
++}
++
++int is_special_user;
++
++static HIME_client_handle *hime_im_client_reopen(HIME_client_handle *hime_ch, Display *dpy)
++{
++//  dbg("hime_im_client_reopen\n");
++  int dbg_msg = getenv("HIME_CONNECT_MSG_ON") != NULL;
++  int sockfd=0;
++  int servlen;
++//  char *addr;
++  Server_IP_port srv_ip_port;
++#if DEBUG
++  u_char *pp;
++#endif
++
++  int uid = getuid();
++  if (uid > 0 && uid < 500) {
++    is_special_user = TRUE;
++  }
++
++  int tcp = FALSE;
++  HIME_client_handle *handle;
++  int rstatus;
++
++//  dbg("hime_im_client_reopen\n");
++  if (!dpy) {
++    dbg("null disp %d\n", hime_ch->fd);
++    goto next;
++  }
++
++  Atom hime_addr_atom = get_hime_addr_atom(dpy);
++  Window hime_win = None;
++
++
++#define MAX_TRY 3
++  int loop;
++
++  if (!is_special_user)
++  for(loop=0; loop < MAX_TRY; loop++) {
++    if ((hime_win=find_hime_window(dpy))!=None || getenv("HIME_IM_CLIENT_NO_AUTO_EXEC"))
++      break;
++    static time_t exec_time;
++
++    if (time(NULL) - exec_time > 1 /* && count < 5 */) {
++      time(&exec_time);
++      dbg("XGetSelectionOwner: old version of hime or hime is not running ??\n");
++      static char execbin[]=HIME_BIN_DIR"/hime";
++      dbg("... try to start a new hime server %s\n", execbin);
++
++      int pid;
++
++      if ((pid=fork())==0) {
++        setenv("HIME_DAEMON", "", TRUE);
++        execl(execbin, "hime", NULL);
++      } else {
++        int status;
++        // hime will daemon()
++        waitpid(pid, &status, 0);
++      }
++    }
++  }
++
++  if (loop == MAX_TRY || hime_win == None) {
++    goto next;
++  }
++
++  Atom actual_type;
++  int actual_format;
++  u_long nitems,bytes_after;
++  char *message_sock = NULL;
++  Atom hime_sockpath_atom = get_hime_sockpath_atom(dpy);
++
++//  printf("hime_sockpath_atom %d\n", hime_sockpath_atom);
++
++  if (!hime_sockpath_atom || XGetWindowProperty(dpy, hime_win, hime_sockpath_atom, 0, 64,
++     False, AnyPropertyType, &actual_type, &actual_format,
++     &nitems,&bytes_after,(u_char **)&message_sock) != Success) {
++#if DBG || 1
++    dbg("XGetWindowProperty 2: old version of hime or hime is not running ??\n");
++#endif
++    goto next;
++  }
++
++  Server_sock_path srv_sock_path;
++  srv_sock_path.sock_path[0] = 0;
++  if (message_sock) {
++    memcpy(&srv_sock_path, message_sock, sizeof(srv_sock_path));
++    XFree(message_sock);
++  } else
++    goto next;
++
++  struct sockaddr_un serv_addr;
++  bzero((char *) &serv_addr,sizeof(serv_addr));
++  serv_addr.sun_family = AF_UNIX;
++  char sock_path[UNIX_PATH_MAX];
++
++  if (srv_sock_path.sock_path[0]) {
++    strcpy(sock_path, srv_sock_path.sock_path);
++  }
++  else {
++    get_hime_im_srv_sock_path(sock_path, sizeof(sock_path));
++  }
++
++//  addr = sock_path;
++  strcpy(serv_addr.sun_path, sock_path);
++#ifdef SUN_LEN
++  servlen = SUN_LEN(&serv_addr);
++#else
++  servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
++#endif
++
++  if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
++    perror("cannot open socket");
++    goto tcp;
++  }
++
++  if (connect(sockfd, (struct sockaddr *)&serv_addr, servlen) < 0) {
++    close(sockfd);
++    sockfd = 0;
++    goto tcp;
++  }
++
++  if (dbg_msg)
++    dbg("connected to unix socket addr %s\n", sock_path);
++  goto next;
++
++  char *message;
++
++tcp:
++  message = NULL;
++
++  if (!hime_addr_atom || XGetWindowProperty(dpy, hime_win, hime_addr_atom, 0, 64,
++     False, AnyPropertyType, &actual_type, &actual_format,
++     &nitems,&bytes_after,(u_char **)&message) != Success) {
++#if DBG || 1
++    dbg("XGetWindowProperty: old version of hime or hime is not running ??\n");
++#endif
++    goto next;
++  }
++
++  if (message) {
++    memcpy(&srv_ip_port, message, sizeof(srv_ip_port));
++    XFree(message);
++  } else
++    goto next;
++
++
++//  dbg("im server tcp port %d\n", ntohs(srv_ip_port.port));
++
++  struct sockaddr_in in_serv_addr;
++  bzero((char *) &in_serv_addr, sizeof(in_serv_addr));
++
++  in_serv_addr.sin_family = AF_INET;
++  in_serv_addr.sin_addr.s_addr = srv_ip_port.ip;
++  in_serv_addr.sin_port = srv_ip_port.port;
++  servlen = sizeof(in_serv_addr);
++
++
++  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
++      perror("cannot open socket");
++      goto next;
++  }
++
++  dbg("sock %d\n", sockfd);
++
++  if (connect(sockfd, (struct sockaddr *)&in_serv_addr, servlen) < 0) {
++    dbg("hime_im_client_open cannot open: ") ;
++    perror("");
++    close(sockfd);
++    sockfd = 0;
++    goto next;
++  }
++
++#if DEBUG
++  pp = (u_char *)&srv_ip_port.ip;
++  if (dbg_msg)
++    dbg("hime client connected to server %d.%d.%d.%d:%d\n",
++        pp[0], pp[1], pp[2], pp[3], ntohs(srv_ip_port.port));
++#endif
++
++  tcp = TRUE;
++
++next:
++  if (!hime_ch)
++    handle = tzmalloc(HIME_client_handle, 1);
++  else {
++    handle = hime_ch;
++  }
++
++  if (sockfd < 0)
++    sockfd = 0;
++
++  if (sockfd > 0) {
++    handle->fd = sockfd;
++    if (tcp) {
++      if (!handle->passwd)
++        handle->passwd = malloc(sizeof(HIME_PASSWD));
++      memcpy(handle->passwd, &srv_ip_port.passwd, sizeof(srv_ip_port.passwd));
++    } else {
++      if (handle->passwd) {
++        free(handle->passwd); handle->passwd = NULL;
++      }
++    }
++  }
++
++  if (handle->fd)  {
++    if (BITON(handle->flag, FLAG_HIME_client_handle_has_focus))
++      hime_im_client_focus_in(handle);
++
++    hime_im_client_set_flags(handle, flags_backup, &rstatus);
++  }
++
++  return handle;
++}
++
++
++static void validate_handle(HIME_client_handle *hime_ch)
++{
++  if (hime_ch->fd > 0)
++    return;
++  if (is_special_user)
++    return;
++
++  hime_im_client_reopen(hime_ch, hime_ch->disp);
++}
++
++
++HIME_client_handle *hime_im_client_open(Display *disp)
++{
++//  dbg("hime_im_client_open\n");
++  HIME_client_handle *handle = hime_im_client_reopen(NULL,  disp);
++  handle->disp = disp;
++  return handle;
++}
++
++void hime_im_client_close(HIME_client_handle *handle)
++{
++  if (!handle)
++	  return;
++  if (handle->fd > 0)
++    close(handle->fd);
++  free(handle->passwd);
++  free(handle);
++}
++
++static int gen_req(HIME_client_handle *handle, u_int req_no, HIME_req *req)
++{
++  validate_handle(handle);
++
++  if (!handle->fd)
++    return 0;
++
++  handle->seq++;
++
++  bzero(req, sizeof(HIME_req));
++
++  req->req_no = req_no;
++  to_hime_endian_4(&req->req_no);
++
++  req->client_win = handle->client_win;
++  to_hime_endian_4(&req->client_win);
++
++  req->input_style = handle->input_style;
++  to_hime_endian_4(&req->input_style);
++
++  req->spot_location.x = handle->spot_location.x;
++  req->spot_location.y = handle->spot_location.y;
++  to_hime_endian_2(&req->spot_location.x);
++  to_hime_endian_2(&req->spot_location.y);
++
++  return 1;
++}
++
++static void error_proc(HIME_client_handle *handle, char *msg)
++{
++  if (!handle->fd)
++    return;
++
++  perror(msg);
++  close(handle->fd);
++  handle->fd = 0;
++  usleep(100000);
++}
++
++typedef struct {
++  struct sigaction apipe;
++} SAVE_ACT;
++static void save_old_sigaction(SAVE_ACT *save_act)
++{
++  save_old_sigaction_single(SIGPIPE, &save_act->apipe);
++}
++static void restore_old_sigaction(SAVE_ACT *save_act)
++{
++  restore_old_sigaction_single(SIGPIPE, &save_act->apipe);
++}
++static int handle_read(HIME_client_handle *handle, void *ptr, int n)
++{
++  int fd = handle->fd;
++
++  if (!fd)
++    return 0;
++
++  SAVE_ACT save_act;
++  save_old_sigaction(&save_act);
++  int r = read(fd, ptr, n);
++
++#if (DBG || 1)
++  if (r < 0)
++    perror("handle_read");
++#endif
++
++  restore_old_sigaction(&save_act);
++
++  if (r<=0)
++    return r;
++  if (handle->passwd)
++    __hime_enc_mem((u_char *)ptr, n, handle->passwd, &handle->passwd->seed);
++  return r;
++}
++
++static int handle_write(HIME_client_handle *handle, void *ptr, int n)
++{
++  int fd = handle->fd;
++
++  if (!fd)
++    return 0;
++
++  u_char *tmp = malloc(n);
++  memcpy(tmp, ptr, n);
++
++  if (handle->passwd)
++    __hime_enc_mem(tmp, n, handle->passwd, &handle->passwd->seed);
++
++  SAVE_ACT save_act;
++#if 1
++  save_old_sigaction(&save_act);
++#endif
++  int r =  write(fd, tmp, n);
++#if 1
++  restore_old_sigaction(&save_act);
++#endif
++  free(tmp);
++
++  return r;
++}
++
++void hime_im_client_focus_in(HIME_client_handle *handle)
++{
++  if (!handle)
++    return;
++  if (is_special_user)
++    return;
++
++  HIME_req req;
++//  dbg("hime_im_client_focus_in\n");
++  handle->flag |= FLAG_HIME_client_handle_has_focus;
++
++  if (!gen_req(handle, HIME_req_focus_in, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_focus_in error");
++  }
++
++  hime_im_client_set_cursor_location(handle, handle->spot_location.x,
++     handle->spot_location.y);
++}
++
++
++void hime_im_client_focus_out(HIME_client_handle *handle)
++{
++  if (!handle)
++    return;
++  if (is_special_user)
++    return;
++
++  HIME_req req;
++//  dbg("hime_im_client_focus_out\n");
++  handle->flag &= ~FLAG_HIME_client_handle_has_focus;
++
++  if (!gen_req(handle, HIME_req_focus_out, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_focus_out error");
++  }
++}
++
++void hime_im_client_focus_out2(HIME_client_handle *handle, char **rstr)
++{
++  HIME_req req;
++  HIME_reply reply;
++
++  if (rstr)
++    *rstr = NULL;
++
++  if (!handle)
++    return;
++
++  if (is_special_user)
++    return;
++
++#if DBG
++  dbg("hime_im_client_focus_out2\n");
++#endif
++  handle->flag &= ~FLAG_HIME_client_handle_has_focus;
++
++  if (!gen_req(handle, HIME_req_focus_out2, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_focus_out error");
++  }
++
++  bzero(&reply, sizeof(reply));
++  if (handle_read(handle, &reply, sizeof(reply)) <=0) {
++    error_proc(handle, "cannot read reply from hime server");
++    return;
++  }
++
++  to_hime_endian_4(&reply.datalen);
++  to_hime_endian_4(&reply.flag);
++
++  if (reply.datalen > 0) {
++    *rstr = (char *)malloc(reply.datalen);
++    if (handle_read(handle, *rstr, reply.datalen) <= 0) {
++      free(*rstr); *rstr = NULL;
++      error_proc(handle, "cannot read reply str from hime server");
++      return;
++    }
++  }
++
++//  dbg("hime_im_client_forward_key_event %x\n", reply.flag);
++
++  return;
++}
++
++static int hime_im_client_forward_key_event(HIME_client_handle *handle,
++                                          HIME_req_t event_type,
++                                          KeySym key, u_int state,
++                                          char **rstr)
++{
++  HIME_reply reply;
++  HIME_req req;
++
++  *rstr = NULL;
++
++  if (is_special_user) {
++      return 0;
++  }
++
++  if (!gen_req(handle, event_type, &req))
++    return 0;
++
++  req.keyeve.key = key;
++  to_hime_endian_4(&req.keyeve.key);
++  req.keyeve.state = state;
++  to_hime_endian_4(&req.keyeve.state);
++
++
++  if (handle_write(handle, &req, sizeof(req)) <= 0) {
++    error_proc(handle, "cannot write to hime server");
++    return FALSE;
++  }
++
++  bzero(&reply, sizeof(reply));
++  if (handle_read(handle, &reply, sizeof(reply)) <=0) {
++    error_proc(handle, "cannot read reply from hime server");
++    return FALSE;
++  }
++
++  to_hime_endian_4(&reply.datalen);
++  to_hime_endian_4(&reply.flag);
++
++  if (reply.datalen > 0) {
++    *rstr = (char *)malloc(reply.datalen);
++    if (handle_read(handle, *rstr, reply.datalen) <= 0) {
++      free(*rstr); *rstr = NULL;
++      error_proc(handle, "cannot read reply str from hime server");
++      return FALSE;
++    }
++  }
++
++//  dbg("hime_im_client_forward_key_event %x\n", reply.flag);
++
++  return reply.flag;
++}
++
++
++// return TRUE if the key is accepted
++int hime_im_client_forward_key_press(HIME_client_handle *handle,
++                                          KeySym key, u_int state,
++                                          char **rstr)
++{
++  int flag;
++  if (!handle)
++    return 0;
++  // in case client didn't send focus in event
++  if (!BITON(handle->flag, FLAG_HIME_client_handle_has_focus)) {
++    hime_im_client_focus_in(handle);
++    handle->flag |= FLAG_HIME_client_handle_has_focus;
++    hime_im_client_set_cursor_location(handle, handle->spot_location.x,
++       handle->spot_location.y);
++  }
++
++//  dbg("hime_im_client_forward_key_press\n");
++  flag = hime_im_client_forward_key_event(
++             handle, HIME_req_key_press, key, state, rstr);
++
++  return ((flag & HIME_reply_key_processed) !=0);
++}
++
++
++// return TRUE if the key is accepted
++int hime_im_client_forward_key_release(HIME_client_handle *handle,
++                                          KeySym key, u_int state,
++                                          char **rstr)
++{
++  int flag;
++  if (!handle)
++    return 0;
++  handle->flag |= FLAG_HIME_client_handle_has_focus;
++//  dbg("hime_im_client_forward_key_release\n");
++  flag = hime_im_client_forward_key_event(
++             handle, HIME_req_key_release, key, state, rstr);
++  return ((flag & HIME_reply_key_processed) !=0);
++}
++
++
++void hime_im_client_set_cursor_location(HIME_client_handle *handle, int x, int y)
++{
++  if (!handle)
++    return;
++  if (is_special_user)
++    return;
++
++//  dbg("hime_im_client_set_cursor_location %d   %d,%d\n", handle->flag, x, y);
++
++  HIME_req req;
++  handle->spot_location.x = x;
++  handle->spot_location.y = y;
++
++  if (!BITON(handle->flag, FLAG_HIME_client_handle_has_focus))
++    return;
++
++  if (!gen_req(handle, HIME_req_set_cursor_location, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_set_cursor_location error");
++  }
++}
++
++// in win32, if win is NULL, this means hime_im_client_set_cursor_location(x,y) is screen position
++void hime_im_client_set_window(HIME_client_handle *handle, Window win)
++{
++  if (!handle)
++    return;
++//  dbg("hime_im_client_set_window %x\n", win);
++
++  if (is_special_user)
++    return;
++  if (!win)
++    return;
++  handle->client_win = win;
++
++// For chrome
++//  hime_im_client_set_cursor_location(handle, handle->spot_location.x, handle->spot_location.y);
++}
++
++void hime_im_client_set_flags(HIME_client_handle *handle, int flags, int *ret_flag)
++{
++  HIME_req req;
++
++#if DBG
++  dbg("hime_im_client_set_flags\n");
++#endif
++
++  if (!handle)
++    return;
++
++  if (is_special_user)
++    return;
++
++  if (!gen_req(handle, HIME_req_set_flags, &req))
++    return;
++
++  req.flag |= flags;
++
++  flags_backup = req.flag;
++
++#if DBG
++  dbg("hime_im_client_set_flags b\n");
++#endif
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_set_flags error");
++  }
++
++#if DBG
++  dbg("hime_im_client_set_flags c\n");
++#endif
++
++  if (handle_read(handle, ret_flag, sizeof(int)) <= 0) {
++    error_proc(handle, "cannot read reply str from hime server");
++  }
++}
++
++
++void hime_im_client_clear_flags(HIME_client_handle *handle, int flags, int *ret_flag)
++{
++  HIME_req req;
++
++  if (!handle)
++    return;
++
++  if (is_special_user)
++    return;
++
++  if (!gen_req(handle, HIME_req_set_flags, &req))
++    return;
++
++  req.flag &= ~flags;
++
++  flags_backup = req.flag;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_set_flags error");
++  }
++
++  if (handle_read(handle, ret_flag, sizeof(int)) <= 0) {
++    error_proc(handle, "cannot read reply str from hime server");
++  }
++}
++
++
++int hime_im_client_get_preedit(HIME_client_handle *handle, char **str, HIME_PREEDIT_ATTR att[], int *cursor ,int *sub_comp_len)
++{
++  *str=NULL;
++  if (!handle)
++    return 0;
++
++  if (is_special_user)
++    return 0;
++
++  int attN, tcursor, str_len;
++#if DBG
++  dbg("hime_im_client_get_preedit\n");
++#endif
++  HIME_req req;
++  if (!gen_req(handle, HIME_req_get_preedit, &req)) {
++err_ret:
++#if DBG
++    dbg("aaaaaaaaaaaaa %x\n", str);
++#endif
++    if (cursor)
++      *cursor=0;
++    *str=strdup("");
++    return 0;
++  }
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_get_preedit error");
++    goto err_ret;
++  }
++
++  str_len=-1; // str_len includes \0
++  if (handle_read(handle, &str_len, sizeof(str_len))<=0)
++    goto err_ret; // including \0
++
++  *str = (char *)malloc(str_len);
++
++  if (handle_read(handle, *str, str_len)<=0)
++    goto err_ret;
++#if DBG
++  dbg("hime_im_client_get_preedit len:%d '%s' \n", str_len, *str);
++#endif
++  attN = -1;
++  if (handle_read(handle, &attN, sizeof(attN))<=0) {
++    goto err_ret;
++  }
++
++//  dbg("attrN:%d\n", attN);
++
++  if (attN>0 && handle_read(handle, att, sizeof(HIME_PREEDIT_ATTR)*attN)<=0) {
++    goto err_ret;
++  }
++
++
++  tcursor=0;
++  if (handle_read(handle, &tcursor, sizeof(tcursor))<=0) {
++    goto err_ret;
++  }
++
++  if (cursor)
++    *cursor = tcursor;
++
++  int tsub_comp_len;
++  tsub_comp_len=0;
++  if (handle_read(handle, &tsub_comp_len, sizeof(tsub_comp_len))<=0) {
++    goto err_ret;
++  }
++  if (sub_comp_len)
++	*sub_comp_len = tsub_comp_len;
++
++#if DBG
++  dbg("jjjjjjjjj %d tcursor:%d\n", attN, tcursor);
++#endif
++  return attN;
++}
++
++
++
++void hime_im_client_reset(HIME_client_handle *handle)
++{
++  if (!handle)
++    return;
++
++  if (is_special_user)
++    return;
++
++  HIME_req req;
++#if DBG
++  dbg("hime_im_client_reset\n");
++#endif
++  if (!gen_req(handle, HIME_req_reset, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_reset error");
++  }
++}
++
++
++void hime_im_client_message(HIME_client_handle *handle, char *message)
++{
++  HIME_req req;
++  short len;
++#if DBG
++  dbg("hime_im_client_message\n");
++#endif
++  if (!gen_req(handle, HIME_req_message, &req))
++    return;
++
++  if (handle_write(handle, &req, sizeof(req)) <=0) {
++    error_proc(handle,"hime_im_client_message error 1");
++  }
++
++  len = strlen(message)+1;
++  if (handle_write(handle, &len, sizeof(len)) <=0) {
++    error_proc(handle,"hime_im_client_message error 2");
++  }
++
++  if (handle_write(handle, message, len) <=0) {
++    error_proc(handle,"hime_im_client_message error 2");
++  }
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.h b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.h
+new file mode 100644
+index 0000000..54d8f44
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-client/hime-im-client.h
+@@ -0,0 +1,96 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#ifndef HIME_IM_CLIENT_H
++#define HIME_IM_CLIENT_H
++
++#ifndef _XSERVER64
++#define _XSERVER64
++#endif
++
++struct HIME_PASSWD;
++
++typedef struct HIME_client_handle_S {
++  int fd;
++  Window client_win;	/* client window */
++  u_int	input_style;	/* input style */
++  XPoint spot_location; /* spot location */
++// below is private data, don't modify them.
++  u_int flag;
++  Display *disp;
++  struct HIME_PASSWD *passwd;
++  u_int seq;
++} HIME_client_handle;
++
++enum {
++  FLAG_HIME_client_handle_has_focus = 1,
++  FLAG_HIME_client_handle_use_preedit = 2,
++  FLAG_HIME_client_handle_raise_window = 0x1000  // for mozilla, dirty fix
++};
++
++enum {
++  FLAG_HIME_srv_ret_status_use_pop_up = 1    // If this is used, we don't need the dirty fix
++};
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++HIME_client_handle *hime_im_client_open(Display *disp);
++void hime_im_client_close(HIME_client_handle *handle);
++void hime_im_client_focus_in(HIME_client_handle *handle);
++void hime_im_client_focus_out(HIME_client_handle *handle);
++void hime_im_client_focus_out2(HIME_client_handle *handle, char **rstr);
++void hime_im_client_set_window(HIME_client_handle *handle, Window win);
++void hime_im_client_set_cursor_location(HIME_client_handle *handle,
++                                        int x, int y);
++/*  rstr returns UTF-8 encoded string, you should use 'free()' to free the
++    memory.
++
++    return boolean:
++      FALSE : the key is rejected, should use client's own result(ASCII key).
++      TRUE : the key is accepted, translated result is in rstr.
++ */
++int hime_im_client_forward_key_press(HIME_client_handle *handle,
++                                          KeySym key, u_int state,
++                                          char **rstr);
++// return some state bits instead of TRUE/FALSE
++int hime_im_client_forward_key_press2(HIME_client_handle *handle,
++                                          KeySym key, u_int state,
++                                          char **rstr);
++int hime_im_client_forward_key_release(HIME_client_handle *handle,
++                                          KeySym key, u_int state,
++                                          char **rstr);
++
++void hime_im_client_set_flags(HIME_client_handle *handle, int flags, int *ret_flags);
++void hime_im_client_clear_flags(HIME_client_handle *handle, int flags, int *ret_flags);
++
++void hime_im_client_reset(HIME_client_handle *handle);
++void hime_im_client_message(HIME_client_handle *handle, char *message);
++
++#include "hime-im-client-attr.h"
++int hime_im_client_get_preedit(HIME_client_handle *handle, char **str, HIME_PREEDIT_ATTR att[], int *cursor, int *sub_comp_len);
++
++Window find_hime_window(Display *dpy);
++
++#ifdef __cplusplus
++}
++#endif
++
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-client/hime-protocol.h b/src/plugins/platforminputcontexts/hime/include/im-client/hime-protocol.h
+new file mode 100644
+index 0000000..b7b4ee3
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-client/hime-protocol.h
+@@ -0,0 +1,95 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <X11/Xlib.h>
++#include "../hime-endian.h"
++
++#define UNIX_PATH_MAX 108
++
++typedef enum {
++  HIME_req_key_press = 1,
++  HIME_req_key_release = 2,
++  HIME_req_focus_in = 4,
++  HIME_req_focus_out = 8,
++  HIME_req_set_cursor_location = 0x10,
++  HIME_req_set_flags = 0x20,
++  HIME_req_get_preedit = 0x40,
++  HIME_req_reset = 0x80,
++  HIME_req_focus_out2 = 0x100,
++  HIME_req_message = 0x200,
++  HIME_req_test_key_press = 0x400,
++  HIME_req_test_key_release = 0x800,
++} HIME_req_t;
++
++
++typedef struct {
++#if 0
++    KeySym key;
++#else
++    u_int key;
++#endif
++    u_int state;
++} KeyEvent;
++
++typedef struct {
++    short x, y;
++} HIMEpoint;
++
++
++typedef struct {
++  u_int req_no;  // to make the im server stateless, more is better
++  u_int client_win;
++  u_int flag;
++  u_int input_style;
++  HIMEpoint spot_location;
++
++  union {
++    KeyEvent keyeve;
++    char dummy[32];   // for future expansion
++  };
++} HIME_req;
++
++
++enum {
++  HIME_reply_key_processed = 1,
++  HIME_reply_key_state_disabled = 2,
++};
++
++
++typedef struct {
++  u_int flag;
++  u_int datalen;    // '\0' shoule be counted if data is string
++} HIME_reply;
++
++
++#define __HIME_PASSWD_N_ (31)
++
++typedef struct HIME_PASSWD {
++  u_int seed;
++  u_char passwd[__HIME_PASSWD_N_];
++} HIME_PASSWD;
++
++typedef struct {
++  u_int ip;
++  u_short port;
++  HIME_PASSWD passwd;
++} Server_IP_port;
++
++typedef struct {
++  char sock_path[UNIX_PATH_MAX];
++} Server_sock_path;
++void __hime_enc_mem(u_char *p, int n, HIME_PASSWD *passwd, u_int *seed);
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-client/hime-send.c b/src/plugins/platforminputcontexts/hime/include/im-client/hime-send.c
+new file mode 100644
+index 0000000..0b22fba
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-client/hime-send.c
+@@ -0,0 +1,26 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "../hime.h"
++#include "hime-im-client.h"
++
++void send_hime_message(Display *dpy, char *s)
++{
++  HIME_client_handle *handle = hime_im_client_open(dpy);
++  hime_im_client_message(handle, s);
++  hime_im_client_close(handle);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-srv.c b/src/plugins/platforminputcontexts/hime/include/im-srv.c
+new file mode 100644
+index 0000000..ac50497
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-srv.c
+@@ -0,0 +1,293 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netinet/in.h>
++#include <string.h>
++#include <netdb.h>
++#include <X11/Xatom.h>
++#include <sys/stat.h>
++#include <arpa/inet.h>
++#include <ifaddrs.h>
++
++#include "hime.h"
++#include "im-client/hime-protocol.h"
++#include "im-srv.h"
++#include <gdk/gdk.h>
++
++int im_sockfd, im_tcp_sockfd;
++Atom get_hime_sockpath_atom(Display *dpy);
++Server_IP_port srv_ip_port;
++static Window prop_win;
++static Atom addr_atom;
++
++void gdk_input_remove	  (gint		     tag);
++
++
++void get_hime_im_srv_sock_path(char *outstr, int outstrN);
++void process_client_req(int fd);
++
++static gboolean cb_read_hime_client_data(GIOChannel *source, GIOCondition condition, gpointer data)
++{
++  int fd=GPOINTER_TO_INT(data);
++
++  process_client_req(fd);
++  return TRUE;
++}
++
++Atom get_hime_addr_atom(Display *dpy);
++
++static void gen_passwd_idx()
++{
++  srv_ip_port.passwd.seed = (rand() >> 1) % __HIME_PASSWD_N_;
++
++  Server_IP_port tsrv_ip_port = srv_ip_port;
++
++  to_hime_endian_4(&srv_ip_port.passwd.seed);
++  XChangeProperty(dpy, prop_win , addr_atom, XA_STRING, 8,
++     PropModeReplace, (unsigned char *)&tsrv_ip_port, sizeof(srv_ip_port));
++
++  XSync(GDK_DISPLAY(), FALSE);
++}
++
++
++
++static gboolean cb_new_hime_client(GIOChannel *source, GIOCondition condition, gpointer data)
++{
++  Connection_type type=(Connection_type) GPOINTER_TO_INT(data);
++#if 0
++  dbg("im-srv: cb_new_hime_client %s\n", type==Connection_type_unix ? "unix":"tcp");
++#endif
++  int newsockfd;
++  socklen_t clilen;
++
++  if (type==Connection_type_unix) {
++    struct sockaddr_un cli_addr;
++
++    bzero(&cli_addr, sizeof(cli_addr));
++    clilen=0;
++    newsockfd = accept(im_sockfd,(struct sockaddr *) & cli_addr, &clilen);
++  } else
++  {
++    struct sockaddr_in cli_addr;
++
++    bzero(&cli_addr, sizeof(cli_addr));
++    clilen=sizeof(cli_addr);
++    newsockfd = accept(im_tcp_sockfd,(struct sockaddr *) & cli_addr, &clilen);
++  }
++
++  if (newsockfd < 0) {
++    perror("accept");
++    return FALSE;
++  }
++
++//  dbg("newsockfd %d\n", newsockfd);
++
++  if (newsockfd >= hime_clientsN - 1) {
++    int prev_hime_clientsN = hime_clientsN, c;
++    hime_clientsN = newsockfd + 1;
++    hime_clients = trealloc(hime_clients, HIME_ENT, hime_clientsN);
++    // Initialize clientstate in useless hime_clients for recognition
++    for(c=prev_hime_clientsN;c<hime_clientsN;c++)
++      hime_clients[c].cs = NULL;
++  }
++
++  bzero(&hime_clients[newsockfd], sizeof(hime_clients[0]));
++
++  hime_clients[newsockfd].tag = g_io_add_watch(g_io_channel_unix_new(newsockfd), G_IO_IN, cb_read_hime_client_data,
++              GINT_TO_POINTER(newsockfd));
++
++  if (type==Connection_type_tcp) {
++    hime_clients[newsockfd].seed = srv_ip_port.passwd.seed;
++    gen_passwd_idx();
++  }
++  hime_clients[newsockfd].type = type;
++  return TRUE;
++}
++
++
++static int get_ip_address(u_int *ip)
++{
++
++#if 0
++  char hostname[64];
++
++  if (gethostname(hostname, sizeof(hostname)) < 0) {
++    perror("cannot get hostname\n");
++    return -1;
++  }
++  dbg("hostname %s\n", hostname);
++  struct hostent *hent;
++
++  if (!(hent=gethostbyname(hostname))) {
++    dbg("cannot call gethostbyname to get IP address");
++    return -1;
++  }
++
++  memcpy(ip, hent->h_addr_list[0], hent->h_length);
++#else
++  struct ifaddrs *ifaddr = NULL, *ifa;
++  int family;
++
++  if (getifaddrs(&ifaddr) == -1) {
++    perror("getifaddrs");
++    exit(EXIT_FAILURE);
++  }
++
++  for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
++      if (!ifa->ifa_addr)
++        continue;
++
++      family = ifa->ifa_addr->sa_family;
++      if (family == AF_INET) {
++        struct sockaddr_in *padd=(struct sockaddr_in *)ifa->ifa_addr;
++        char *ipaddr = inet_ntoa(padd->sin_addr);
++        if (!strcmp(ipaddr, "127.0.0.1"))
++          continue;
++        dbg("ip addr %s\n", ipaddr);
++        memcpy(ip, &padd->sin_addr.s_addr, INET_ADDRSTRLEN);
++        break;
++      }
++  }
++
++  freeifaddrs(ifaddr);
++#endif
++  return 0;
++}
++
++
++
++void start_pipe_svr();
++
++void init_hime_im_serv(Window win)
++{
++  dbg("init_hime_im_serv\n");
++
++  int servlen;
++  prop_win = win;
++  struct sockadd_un;
++  struct sockaddr_un serv_addr;
++
++  // unix socket
++  bzero(&serv_addr,sizeof(serv_addr));
++  serv_addr.sun_family = AF_UNIX;
++  char sock_path[UNIX_PATH_MAX];
++  get_hime_im_srv_sock_path(sock_path, sizeof(sock_path));
++  strcpy(serv_addr.sun_path, sock_path);
++
++#ifdef SUN_LEN
++  servlen = SUN_LEN (&serv_addr);
++#else
++  servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
++#endif
++
++  dbg("-- %s\n",serv_addr.sun_path);
++  struct stat st;
++
++  if (!stat(serv_addr.sun_path, &st)) {
++    if (unlink(serv_addr.sun_path) < 0) {
++      char tt[512];
++      snprintf(tt, sizeof(tt), "unlink error %s", serv_addr.sun_path);
++      perror(tt);
++    }
++  }
++
++
++  if ((im_sockfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0) {
++    perror("cannot open unix socket");
++    exit(-1);
++  }
++
++  if (bind(im_sockfd, (struct sockaddr *) &serv_addr, servlen) < 0) {
++    perror("cannot bind");
++    exit(-1);
++  }
++
++  listen(im_sockfd,2);
++
++  dbg("im_sockfd:%d\n", im_sockfd);
++
++  g_io_add_watch(g_io_channel_unix_new(im_sockfd), G_IO_IN, cb_new_hime_client,
++                GINT_TO_POINTER(Connection_type_unix));
++
++  Display *dpy = GDK_DISPLAY();
++
++  Server_sock_path srv_sockpath;
++  strcpy(srv_sockpath.sock_path, sock_path);
++  Atom sockpath_atom = get_hime_sockpath_atom(dpy);
++  XChangeProperty(dpy, prop_win , sockpath_atom, XA_STRING, 8,
++     PropModeReplace, (unsigned char *)&srv_sockpath, sizeof(srv_sockpath));
++
++  addr_atom = get_hime_addr_atom(dpy);
++  XSetSelectionOwner(dpy, addr_atom, win, CurrentTime);
++
++  if (!hime_remote_client) {
++    dbg("connection via TCP is disabled\n");
++    return;
++  }
++
++  // tcp socket
++  if (get_ip_address(&srv_ip_port.ip) < 0)
++    return;
++
++  if ((im_tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
++    perror("cannot open tcp socket");
++    exit(-1);
++  }
++
++//  dbg("socket succ\n");
++
++  struct sockaddr_in serv_addr_tcp;
++  u_short port;
++
++  for(port=9999; port < 20000; port++)
++  {
++    // tcp socket
++    bzero(&serv_addr_tcp, sizeof(serv_addr_tcp));
++    serv_addr_tcp.sin_family = AF_INET;
++
++    serv_addr_tcp.sin_addr.s_addr = htonl(INADDR_ANY);
++    serv_addr_tcp.sin_port = htons(port);
++    if (bind(im_tcp_sockfd, (struct sockaddr *) &serv_addr_tcp, sizeof(serv_addr_tcp)) == 0)
++      break;
++  }
++
++  srv_ip_port.port = serv_addr_tcp.sin_port;
++  dbg("server port bind to %s:%d\n", inet_ntoa(serv_addr_tcp.sin_addr), port);
++  time_t t;
++  srand(time(&t));
++
++  int i;
++  for(i=0; i < __HIME_PASSWD_N_; i++) {
++    srv_ip_port.passwd.passwd[i] = (rand()>>2) & 0xff;
++  }
++
++  if (listen(im_tcp_sockfd, 5) < 0) {
++    perror("cannot listen: ");
++    exit(1);
++  }
++
++  dbg("after listen\n");
++
++
++  gen_passwd_idx();
++
++  g_io_add_watch(g_io_channel_unix_new(im_tcp_sockfd), G_IO_IN, cb_new_hime_client,
++                GINT_TO_POINTER(Connection_type_tcp));
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/im-srv.h b/src/plugins/platforminputcontexts/hime/include/im-srv.h
+new file mode 100644
+index 0000000..4bd9657
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/im-srv.h
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef enum {
++  Connection_type_unix = 1,
++  Connection_type_tcp = 2
++} Connection_type;
++
++typedef struct {
++  ClientState *cs;
++  int tag;
++  u_int seed;
++  Connection_type type;
++  int fd;
++} HIME_ENT;
++
++extern HIME_ENT *hime_clients;
++extern int hime_clientsN;
++extern Server_IP_port srv_ip_port;
+diff --git a/src/plugins/platforminputcontexts/hime/include/lang.c b/src/plugins/platforminputcontexts/hime/include/lang.c
+new file mode 100644
+index 0000000..d7035e8
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/lang.c
+@@ -0,0 +1,47 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "lang.h"
++
++gboolean is_chs;
++char *tsin32_f="tsin32";
++
++void set_is_chs()
++{
++  char *lc_ctype = getenv("LC_CTYPE");
++  char *lc_all = getenv("LC_ALL");
++  char *lang = getenv("LANG");
++  if (!lc_ctype && lang)
++    lc_ctype = lang;
++
++  if (lc_all)
++    lc_ctype = lc_all;
++
++  if (!lc_ctype)
++    lc_ctype = "zh_TW.Big5";
++  dbg("hime get env LC_CTYPE=%s  LC_ALL=%s  LANG=%s\n", lc_ctype, lc_all, lang);
++
++  if (strstr(lc_ctype, "zh_CN") || 0) {
++    is_chs = TRUE;
++  }
++
++  if (is_chs) {
++    tsin32_f = "s-tsin32";
++    dbg("is simplified chinese\n");
++  }
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/lang.h b/src/plugins/platforminputcontexts/hime/include/lang.h
+new file mode 100644
+index 0000000..c54a2b6
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/lang.h
+@@ -0,0 +1,3 @@
++extern gboolean is_chs;
++extern char *tsin32_f;
++void set_is_chs();
+diff --git a/src/plugins/platforminputcontexts/hime/include/os-dep.h b/src/plugins/platforminputcontexts/hime/include/os-dep.h
+new file mode 100644
+index 0000000..1b2fb01
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/os-dep.h
+@@ -0,0 +1,18 @@
++#ifndef OS_DEP_H
++#define OS_DEP_H
++
++typedef char unich_t;
++void unix_exec(char *fmt,...);
++
++#include <X11/Xlib.h>
++#include <X11/Xlocale.h>
++#include <X11/keysym.h>
++
++#include <glib.h>
++#if GLIB_CHECK_VERSION(2,29,8)
++#define G_CONST_RETURN const
++#endif
++
++#include <gdk/gdkx.h>
++
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/pho-status.h b/src/plugins/platforminputcontexts/hime/include/pho-status.h
+new file mode 100644
+index 0000000..f31f8a4
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/pho-status.h
+@@ -0,0 +1,7 @@
++enum {
++  PHO_STATUS_REJECT=1,
++  PHO_STATUS_OK=2,
++  PHO_STATUS_OK_NEW=4,
++  PHO_STATUS_PINYIN_LEFT=8,
++  PHO_STATUS_TONE=16,
++};
+diff --git a/src/plugins/platforminputcontexts/hime/include/pho.c b/src/plugins/platforminputcontexts/hime/include/pho.c
+new file mode 100644
+index 0000000..bcefa8c
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/pho.c
+@@ -0,0 +1,869 @@
++/* Copyright (C) 1994-2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "pho.h"
++#include <sys/stat.h>
++#include <stdlib.h>
++#include "gtab.h"
++#include "gst.h"
++#include "pho-status.h"
++
++PHO_ST poo;
++
++extern PHO_ITEM *ch_pho;
++
++PHOKBM phkbm;
++extern int text_pho_N;
++gboolean b_hsu_kbm;
++extern PIN_JUYIN *pin_juyin;
++int pin_juyinN;
++
++gboolean full_char_proc(KeySym keysym);
++void hide_win_pho();
++void ClrSelArea();
++
++#define MAX_HASH_PHO 27
++u_short hash_pho[MAX_HASH_PHO+1];
++
++static char typ_pho_len[]={5, 2, 4, 3};
++
++gboolean same_query_show_pho_win();
++
++gboolean typ_pho_empty()
++{
++  return !poo.typ_pho[0] &&!poo.typ_pho[1] &&!poo.typ_pho[2] &&!poo.typ_pho[3];
++}
++
++gboolean pho_has_input()
++{
++  return !typ_pho_empty() || same_query_show_pho_win();
++}
++
++phokey_t pho2key(char typ_pho[])
++{
++  phokey_t key=typ_pho[0];
++  int i;
++
++  if (key==BACK_QUOTE_NO)
++    return (BACK_QUOTE_NO<<9) | typ_pho[1];
++
++  for(i=1; i < 4; i++) {
++    key =  typ_pho[i] | (key << typ_pho_len[i]) ;
++  }
++
++  return key;
++}
++
++void key_typ_pho(phokey_t phokey, u_char rtyp_pho[])
++{
++  rtyp_pho[3] = phokey & 7;
++  phokey >>= 3;
++  rtyp_pho[2] = phokey & 0xf;
++  phokey >>=4;
++  rtyp_pho[1] = phokey & 0x3;
++  phokey >>=2;
++  rtyp_pho[0] = phokey;
++}
++
++
++void mask_key_typ_pho(phokey_t *key)
++{
++  if (poo.typ_pho[0] == BACK_QUOTE_NO)
++    return;
++  if (!poo.typ_pho[0]) *key &= ~(31<<9);
++  if (!poo.typ_pho[1]) *key &= ~(3<<7);
++  if (!poo.typ_pho[2]) *key &= ~(15<<3);
++  if (!poo.typ_pho[3]) *key &= ~(7);
++}
++
++#define TKBM 0
++#define MIN_M_PHO 5
++
++static void find_match_phos(u_char mtyp_pho[4], int *mcount, int newkey)
++{
++      int vv;
++      phokey_t key = pho2key(poo.typ_pho);
++
++      mask_key_typ_pho(&key);
++#if TKBM
++      dbg("-------------------- %d --", poo.typ_pho[3]);
++      prph(key);
++      dbg("\n");
++#endif
++      for (vv = hash_pho[(int)poo.typ_pho[0]]; vv < hash_pho[(int)poo.typ_pho[0]+1]; vv++) {
++        phokey_t ttt=idx_pho[vv].key;
++
++        if (newkey!=' ' && !poo.typ_pho[3])
++          mask_key_typ_pho(&ttt);
++
++        if (ttt > key)
++          break;
++
++        int count = 0;
++
++        int i;
++        for(i=idx_pho[vv].start; i < idx_pho[vv+1].start; i++) {
++          if (utf8_sz(pho_idx_str(i)) > 1) {
++#if 0
++            utf8_putchar(ch_pho[i].ch);
++            dbg(" ");
++#endif
++            count++;
++          }
++        }
++
++        if (*mcount < count) {
++          *mcount = count;
++          memcpy(mtyp_pho, poo.typ_pho, sizeof(poo.typ_pho));
++#if TKBM
++          dbg("count %d\n", count);
++#endif
++          if (*mcount > MIN_M_PHO)
++            break;
++        }
++      }
++}
++
++gboolean inph_typ_pho_pinyin(int newkey);
++
++static int typ_pho_status()
++{
++  return poo.typ_pho[3] ? PHO_STATUS_OK_NEW:PHO_STATUS_OK;
++}
++
++int inph_typ_pho(KeySym newkey)
++{
++  int i;
++  int insert = -1;
++
++  if (pin_juyin) {
++    return inph_typ_pho_pinyin(newkey);
++  }
++
++  if (poo.typ_pho[0]==BACK_QUOTE_NO) {
++    poo.typ_pho[1]=(char)newkey;
++    poo.inph[1]=newkey;
++    return PHO_STATUS_OK;
++  }
++
++  int max_in_idx;
++  for(max_in_idx=3; max_in_idx>=0 && !poo.typ_pho[max_in_idx]; max_in_idx--);
++
++  // try insert mode first
++  if (insert < 0)
++  for(i=0; i < 3; i++) {
++    char num = phkbm.phokbm[(int)newkey][i].num;
++    int typ = phkbm.phokbm[(int)newkey][i].typ;
++
++    if (num && !poo.inph[typ] && typ>max_in_idx) {
++      poo.inph[typ] = newkey;
++      poo.typ_pho[typ] = num;
++#if TKBM
++      dbg("insert typ %d\n", typ);
++#endif
++      insert = typ;
++      break;
++    }
++  }
++
++  if (insert < 0) {
++    // then overwrite mode
++    for(i=0; i < 3; i++) {
++      char num = phkbm.phokbm[newkey][i].num;
++      int typ = phkbm.phokbm[newkey][i].typ;
++
++      if (num) {
++        poo.inph[typ] = newkey;
++        poo.typ_pho[typ] = num;
++        insert = typ;
++        break;
++      }
++    }
++  }
++
++//  dbg("newkey %c\n", newkey);
++
++  int mcount = 0;
++  u_char mtyp_pho[4];
++
++  int a;
++
++  for(a=0; a < 3; a++) {
++    char num = phkbm.phokbm[(int)poo.inph[0]][a].num;
++    char typ = phkbm.phokbm[(int)poo.inph[0]][a].typ;
++
++    if (typ == 3)
++      continue;
++
++    if (num) {
++      if (typ==2 && poo.typ_pho[0] && !poo.typ_pho[2])
++        poo.typ_pho[0] = 0;
++      poo.typ_pho[(int)typ] = num;
++#if TKBM
++      dbg("%d num %d\n",a, num);
++#endif
++      find_match_phos(mtyp_pho, &mcount, newkey);
++    }
++
++    for(i=0; i < 3; i++) {
++      char num = phkbm.phokbm[(int)poo.inph[2]][i].num;
++      char typ = phkbm.phokbm[(int)poo.inph[2]][i].typ;
++
++      if (!num)
++        break;
++
++      if (typ!=2)
++        continue;
++
++      poo.typ_pho[(int)typ] = num;
++
++      find_match_phos(mtyp_pho, &mcount, newkey);
++
++      if (mcount > MIN_M_PHO) {
++        return typ_pho_status();
++      }
++    }
++
++
++    find_match_phos(mtyp_pho, &mcount, newkey);
++
++    if (mcount > MIN_M_PHO) {
++      return typ_pho_status();
++    }
++  }
++
++  if (mcount) {
++    memcpy(poo.typ_pho, mtyp_pho, sizeof(poo.typ_pho));
++    return typ_pho_status();
++  }
++
++  return PHO_STATUS_REJECT;
++}
++
++
++void clrin_pho()
++{
++  bzero(poo.typ_pho,sizeof(poo.typ_pho));
++  bzero(poo.inph,sizeof(poo.inph));
++  poo.maxi=poo.ityp3_pho=0;
++  poo.cpg=0;
++
++  if (hime_pop_up_win && !same_query_show_pho_win())
++    hide_win_pho();
++}
++
++void disp_pho(int index, char *phochar);
++void clr_in_area_pho()
++{
++  int i;
++
++  clrin_pho();
++  for(i=0; i < text_pho_N; i++)
++    disp_pho(i, "  ");
++}
++
++
++static void disp_in_area_pho()
++{
++  int i;
++
++  text_pho_N = pin_juyin?7:4;
++  if (pin_juyin) {
++    for(i=0;i<text_pho_N;i++) {
++      disp_pho(i, &poo.inph[i]);
++    }
++  } else {
++    for(i=0;i<4;i++) {
++      if (i==1 && poo.typ_pho[0]==BACK_QUOTE_NO) {
++        disp_pho(i, &poo.inph[1]);
++      }
++      else
++        disp_pho(i, &pho_chars[i][poo.typ_pho[i]*3]);
++    }
++  }
++}
++
++static int qcmp_count(const void *aa, const void *bb)
++{
++  PHO_ITEM *a = (PHO_ITEM *)aa;
++  PHO_ITEM *b = (PHO_ITEM *)bb;
++
++  return b->count - a->count;
++}
++
++void disp_pho_sel(char *s);
++
++static void ClrPhoSelArea()
++{
++  disp_pho_sel("");
++}
++
++
++extern char *TableDir;
++extern char phofname[128];
++
++gboolean get_start_stop_idx(phokey_t key, int *start_i, int *stop_i)
++{
++  int typ_pho0 = key >> 9;
++  int vv=hash_pho[typ_pho0];
++
++  while (vv<idxnum_pho) {
++    if (idx_pho[vv].key>=key) break;
++    else
++      vv++;
++  }
++
++  if (vv >= idxnum_pho || idx_pho[vv].key != key)
++    return FALSE;
++
++  *start_i=idx_pho[vv].start;
++  *stop_i=idx_pho[vv+1].start;
++
++  return TRUE;
++}
++
++// given the pho key & the utf8 char, return the idx in ch_pho
++int ch_key_to_ch_pho_idx(phokey_t phkey, char *utf8)
++{
++  int start_i, stop_i;
++
++  get_start_stop_idx(phkey, &start_i, &stop_i);
++
++  int i;
++  for(i=start_i; i<stop_i; i++) {
++    char *ch = pho_idx_str(i);
++    int u8len = utf8_sz(ch);
++    if (!memcmp(ch, utf8, u8len)) {
++      return i;
++    }
++  }
++
++//  prph(phkey);
++//  dbg("error found   %c%c", *big5, *(big5+1));
++  return -1;
++}
++
++
++void inc_pho_count(phokey_t key, int ch_idx)
++{
++  int start_i, stop_i;
++
++  if (!phonetic_char_dynamic_sequence)
++    return;
++
++  get_start_stop_idx(key, &start_i, &stop_i);
++
++//  dbg("start_i %d %d    %d %d\n", start_i, stop_i, poo.start_idx, poo.stop_idx);
++
++  ch_pho[ch_idx].count++;
++//  dbg("count %d\n", ch_pho[ch_idx].count);
++
++  qsort(&ch_pho[start_i], stop_i - start_i, sizeof(PHO_ITEM), qcmp_count);
++#if 0
++  int i;
++  for(i=start_i; i < stop_i; i++) {
++    dbg("uuuu %c%c%c %d\n", ch_pho[i].ch[0], ch_pho[i].ch[1],
++      ch_pho[i].ch[2], ch_pho[i].count);
++  }
++#endif
++
++  FILE *fw;
++
++//  dbg("phofname %s\n", phofname);
++  if ((fw=fopen(phofname,"rb+"))==NULL) {
++    p_err("err %s\n", phofname);
++  }
++
++  if (fseek(fw, ch_pho_ofs + sizeof(PHO_ITEM) * start_i, SEEK_SET) < 0)
++    p_err("fseek err");
++#if 1
++  if (fwrite(&ch_pho[start_i], sizeof(PHO_ITEM), stop_i - start_i, fw) <= 0)
++    p_err("fwrite err");
++#endif
++  fclose(fw);
++}
++
++
++void lookup_gtab(char *ch);
++gboolean is_gtab_query_mode();
++void set_gtab_target_displayed();
++
++#include "gtab-buf.h"
++
++void putkey_pho(u_short key, int idx)
++{
++  char *pho_str = pho_idx_str(idx);
++
++  if (poo.same_pho_query_state==SAME_PHO_QUERY_pho_select && ggg.gbufN)
++    insert_gbuf_nokey(pho_str);
++  else
++    send_text(pho_str);
++
++  lookup_gtab(pho_str);
++
++  inc_pho_count(key, idx);
++
++  clr_in_area_pho();
++  ClrSelArea();
++
++  if (is_gtab_query_mode())
++    set_gtab_target_displayed();
++}
++
++void load_pin_juyin();
++void recreate_win1_if_nessary();
++
++void load_tab_pho_file()
++{
++  pho_load();
++
++  bzero(poo.typ_pho,sizeof(poo.typ_pho));
++
++  u_int ttt=0;
++  int i;
++  for(i=0; i<MAX_HASH_PHO; i++) {
++    if (idx_pho[ttt].key >> 9 == i)
++      hash_pho[i]=ttt;
++    else {
++      continue;
++    }
++
++    while (ttt < idxnum_pho && idx_pho[ttt].key >> 9 == i)
++      ttt++;
++  }
++
++  for(i=MAX_HASH_PHO; !hash_pho[i];  i--)
++    hash_pho[i]=idxnum_pho;
++
++  char kbmfname[MAX_HIME_STR];
++  FILE *fr;
++
++  free(pin_juyin);
++  pin_juyin = NULL;
++
++  if (!strstr(pho_kbm_name, "pinyin")) {
++    text_pho_N = 4;
++  } else {
++    load_pin_juyin();
++  }
++
++  if (strcmp(pho_kbm_name, "hsu"))
++    b_hsu_kbm = FALSE;
++  else
++    b_hsu_kbm = TRUE;
++
++  char pho_kbm_name_kbm[128];
++
++  strcat(strcpy(pho_kbm_name_kbm, pho_kbm_name), ".kbm");
++  dbg("phokbm_name: %s\n", pho_kbm_name_kbm);
++
++  get_sys_table_file_name(pho_kbm_name_kbm, kbmfname);
++
++  if ((fr=fopen(kbmfname,"rb"))==NULL)
++     p_err("Cannot open %s", kbmfname);
++
++  dbg("kbmfname %s\n", kbmfname);
++
++  fread(&phkbm,sizeof(phkbm),1,fr);
++  fclose (fr);
++  phkbm.selkeyN = strlen(pho_selkey);
++
++  dbg("pho_selkey %s\n", pho_selkey);
++
++  recreate_win1_if_nessary();
++#if 0
++  for(i='A'; i <= 'z'; i++)
++    dbg("%c %d %d\n", i, phkbm.phokbm[i][0].num, phkbm.phokbm[i][0].typ);
++#endif
++}
++
++
++void show_win_pho();
++
++void init_tab_pho()
++{
++  if (!ch_pho) {
++    load_tab_pho_file();
++  }
++
++  show_win_pho();
++  clr_in_area_pho();
++}
++
++static char *pho_idx_str_markup(int ii)
++{
++  char *pho_str = pho_idx_str(ii);
++  if (!strcmp(pho_str, "<"))
++    pho_str = "&lt;";
++  else
++  if (!strcmp(pho_str, ">"))
++    pho_str = "&gt;";
++  return pho_str;
++}
++
++
++gboolean shift_char_proc(KeySym key, int kbstate);
++gboolean pre_punctuation(KeySym xkey);
++void pho_play(phokey_t key);
++void close_gtab_pho_win();
++gboolean pre_punctuation_hsu(KeySym xkey);
++void case_inverse(KeySym *xkey, int shift_m);
++
++int feedkey_pho(KeySym xkey, int kbstate)
++{
++  int ctyp = 0;
++  static unsigned int vv, ii;
++  static phokey_t key;
++  char *pp=NULL;
++  char kno;
++  int i,j,jj=0,kk=0;
++  char out_buffer[512];
++  int out_bufferN;
++  int shift_m=kbstate&ShiftMask;
++  int ctrl_m=kbstate&ControlMask;
++
++  if (ctrl_m)
++    return 0;
++
++
++  if (kbstate&LockMask) {
++    if (xkey >= 0x7e || xkey < ' ')
++      return FALSE;
++    if (hime_capslock_lower)
++      case_inverse(&xkey, shift_m);
++    send_ascii(xkey);
++    return 1;
++  }
++
++  if (xkey >= 'A' && xkey <='Z' && poo.typ_pho[0]!=BACK_QUOTE_NO)
++    xkey+=0x20;
++
++  switch (xkey) {
++    case XK_Escape:
++      if (typ_pho_empty())
++        return 0;
++      ClrPhoSelArea();
++      clr_in_area_pho();
++      if (is_gtab_query_mode())
++        close_gtab_pho_win();
++      return 1;
++    case XK_BackSpace:
++      poo.ityp3_pho=0;
++      for(j=3;j>=0;j--) if (poo.typ_pho[j]) {
++        poo.typ_pho[j]=0;
++        if (typ_pho_empty()) {
++          ClrSelArea();
++          clr_in_area_pho();
++          return 1;
++        }
++        break;
++      }
++
++      if (j<0)
++        return 0;
++
++      goto llll3;
++    case '<':
++       if (!poo.ityp3_pho) {
++         return pre_punctuation(xkey);
++       }
++       if (poo.cpg >= phkbm.selkeyN)
++         poo.cpg -= phkbm.selkeyN;
++       goto proc_state;
++    case ' ':
++      if (!poo.typ_pho[0] && !poo.typ_pho[1] && !poo.typ_pho[2]) {
++        if (current_CS->b_half_full_char)
++          return full_char_proc(xkey);
++        return 0;
++      }
++
++//      dbg("poo.ityp3_pho %d\n", poo.ityp3_pho);
++      if (!poo.ityp3_pho) {
++        poo.ityp3_pho = TRUE;
++        goto lll1;
++      }
++
++      ii = poo.start_idx+ poo.cpg + phkbm.selkeyN;
++
++      if (ii < poo.stop_idx) {
++        poo.cpg += phkbm.selkeyN;
++        dbg("spc pool.cpg %d\n", poo.cpg);
++      } else {
++        if (poo.cpg) {
++          poo.cpg=0;
++          ii=poo.start_idx;
++        } else {
++          putkey_pho(key, poo.start_idx);
++          return 1;
++        }
++      }
++
++      goto disp;
++   default:
++      if (xkey >= 127 || xkey < ' ')
++        return 0;
++
++      if (shift_m) {
++//        return shift_char_proc(xkey, kbstate);
++        if (pre_punctuation(xkey))
++          return 1;
++        return 0;
++      }
++
++//    dbg("poo.maxi:%d  %d\n", poo.maxi, poo.cpg);
++
++      if ((pp=strchr(pho_selkey, xkey)) && poo.maxi && poo.ityp3_pho) {
++        int c=pp-pho_selkey;
++
++        if (c<poo.maxi) {
++          putkey_pho(key, poo.start_idx + poo.cpg + c);
++        }
++        return 1;
++      }
++
++      if (poo.ityp3_pho && !poo.cpg) {
++//        dbg("poo.start_idx: %d\n", poo.start_idx);
++        putkey_pho(key, poo.start_idx);
++      }
++
++//      poo.cpg=0;
++  }
++
++lll1:
++  inph_typ_pho(xkey);
++//  dbg("typ_pho %x %x\n", poo.typ_pho[0], poo.typ_pho[1]);
++
++  if (hime_pop_up_win)
++    show_win_pho();
++
++  if (poo.typ_pho[3])
++    ctyp = 3;
++
++  jj=0;
++  kk=1;
++llll2:
++  if (ctyp == 3) {
++       poo.ityp3_pho=1;  /* last key is entered */
++  }
++llll3:
++
++  key = pho2key(poo.typ_pho);
++
++#if    0
++  dbg("poo.typ_pho %d %d %d %d\n", poo.typ_pho[0], poo.typ_pho[1], poo.typ_pho[2], poo.typ_pho[3]);
++#endif
++  if (!key) {
++    return pre_punctuation_hsu(xkey);
++  }
++
++  pho_play(key);
++
++  vv=hash_pho[(int)poo.typ_pho[0]];
++  phokey_t ttt;
++  ttt=0xffff;
++
++  while (vv < idxnum_pho) {
++    ttt=idx_pho[vv].key;
++    mask_key_typ_pho(&ttt);
++
++    if (ttt>=key)
++      break;
++    else
++      vv++;
++  }
++
++//  dbg("vv %d %d\n", vv, idxnum_pho);
++
++  if (ttt > key || (poo.ityp3_pho && idx_pho[vv].key != key) ) {
++//    dbg("not found\n");
++    while (jj<4) {
++      while(kk<3)
++        if (phkbm.phokbm[(int)poo.inph[jj]][kk].num ) {
++
++          if (kk) {
++            ctyp=phkbm.phokbm[(int)poo.inph[jj]][kk-1].typ;
++            poo.typ_pho[ctyp]=0;
++          }
++
++          kno=phkbm.phokbm[(int)poo.inph[jj]][kk].num;
++          ctyp=phkbm.phokbm[(int)poo.inph[jj]][kk].typ;
++          poo.typ_pho[ctyp]=kno;
++          kk++;
++          goto llll2;
++        }
++        else
++          kk++;
++      jj++;
++      kk=1;
++    }
++
++    bell();
++    poo.ityp3_pho=poo.typ_pho[3]=0;
++    disp_in_area_pho();
++    return 1;
++  }
++
++proc_state:
++  disp_in_area_pho();
++  poo.start_idx = ii = idx_pho[vv].start;
++  poo.stop_idx = idx_pho[vv+1].start;
++
++//  dbg("poo.start_idx: %d %d\n", poo.start_idx, poo.stop_idx);
++
++  if (poo.typ_pho[0]==L_BRACKET_NO||poo.typ_pho[0]==R_BRACKET_NO || (poo.typ_pho[0]==BACK_QUOTE_NO && poo.typ_pho[1]))
++     poo.ityp3_pho = 1;
++
++  ii+=poo.cpg;
++
++  if (poo.ityp3_pho && poo.stop_idx - poo.start_idx==1) {
++    putkey_pho(key, ii);
++    poo.maxi=poo.ityp3_pho=0;
++    return 1;
++  }
++
++disp:
++  i=0;
++  out_bufferN=0;
++  out_buffer[0]=0;
++
++  if (poo.ityp3_pho) {
++//    dbg("poo.cpg %d\n", poo.cpg);
++
++    while(i< phkbm.selkeyN  && ii < poo.stop_idx) {
++      char tt[512];
++      sprintf(tt, "<span foreground=\"%s\">%c</span>",
++         hime_sel_key_color, pho_selkey[i]);
++      int ttlen = strlen(tt);
++      memcpy(out_buffer+out_bufferN, tt, ttlen);
++      out_bufferN+=ttlen;
++//      strcat(out_buffer, tt);
++      char *pho_str = pho_idx_str_markup(ii);
++      int len = strlen(pho_str);
++      memcpy(&out_buffer[out_bufferN], pho_str, len);
++      out_bufferN+=len;
++      out_buffer[out_bufferN++] = ' ';
++
++      ii++;
++      i++;
++    }
++
++    char *tt = poo.cpg ? "&lt;" : " ";
++    int ttlen = strlen(tt);
++    memcpy(out_buffer+out_bufferN, tt, ttlen);
++    out_bufferN+=ttlen;
++
++    if (ii < poo.stop_idx) {
++      out_buffer[out_bufferN++] = poo.cpg ? '\\' : ' ';
++      tt = "&gt;";
++      ttlen = strlen(tt);
++      memcpy(out_buffer+out_bufferN, tt, ttlen);
++      out_bufferN+=strlen(tt);
++    }
++
++    poo.maxi=i;
++  } else {
++    while(i<phkbm.selkeyN  && ii < poo.stop_idx) {
++      char *pho_str = pho_idx_str_markup(ii);
++      int len = strlen(pho_str);
++      memcpy(&out_buffer[out_bufferN], pho_str, len);
++      out_bufferN+=len;
++
++      ii++;
++      i++;
++    }
++    poo.maxi=i;
++  }
++
++  out_buffer[out_bufferN]=0;
++  disp_pho_sel(out_buffer);
++
++  return 1;
++}
++
++static char typ_pho_no_to_xkey(int typ, u_char num)
++{
++  int i, j;
++
++  for(i=' '; i < 127; i++)
++    for(j=0; j < 3; j++)
++      if (phkbm.phokbm[i][j].typ == typ && phkbm.phokbm[i][j].num == num)
++        return i;
++
++  return 0;
++}
++
++
++void start_gtab_pho_query(char *utf8)
++{
++  phokey_t phokeys[32];
++  int phokeysN, i;
++
++  phokeysN = utf8_pho_keys(utf8, phokeys);
++  if (phokeysN <= 0)
++    return;
++
++  u_char rtyp_pho[4];
++  bzero(rtyp_pho, sizeof(rtyp_pho));
++  key_typ_pho(phokeys[0], rtyp_pho);
++
++  char xkeys[4];
++  bzero(xkeys, sizeof(xkeys));
++
++  for(i=0; i < 4; i++) {
++    if (!rtyp_pho[i])
++      continue;
++
++    xkeys[i] = typ_pho_no_to_xkey(i, rtyp_pho[i]);
++  }
++
++  if (!xkeys[3])
++    xkeys[3] = ' ';
++
++  for(i=0; i < 4; i++) {
++    feedkey_pho(xkeys[i], 0);
++  }
++}
++
++
++void pho_reset()
++{
++}
++
++#include "im-client/hime-im-client-attr.h"
++extern GtkWidget *gwin_pho;
++
++int pho_get_preedit(char *str, HIME_PREEDIT_ATTR attr[], int *cursor, int *sub_comp_len)
++{
++  *sub_comp_len = !typ_pho_empty();;
++  if (gwin_pho && GTK_WIDGET_VISIBLE(gwin_pho))
++    *sub_comp_len|=2;
++  *cursor = 0;
++  str[0]=0;
++  return 0;
++}
++
++static PHO_ST temp_pho_st;
++void pho_save_gst()
++{
++  temp_pho_st = poo;
++}
++
++void pho_restore_gst()
++{
++  poo = temp_pho_st;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/pho.h b/src/plugins/platforminputcontexts/hime/include/pho.h
+new file mode 100644
+index 0000000..da76a80
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/pho.h
+@@ -0,0 +1,92 @@
++/* Copyright (C) 1995-2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef u_short phokey_t;
++
++typedef struct {
++  char selkeyN;
++  struct {
++    char num, typ;
++  } phokbm[128][3];  // for 26 keys pho, it may have up-to 3 pho char for a key
++} PHOKBM;
++
++extern PHOKBM phkbm;
++
++typedef struct {
++  char ch[CH_SZ];
++  int count;
++} PHO_ITEM;
++
++typedef struct {
++  phokey_t key;
++  u_short start;
++} PHO_IDX;
++
++
++typedef struct {
++  char pinyin[7];
++  phokey_t key;
++} PIN_JUYIN;
++
++#define MAX_PHRASE_LEN (32)
++#define MAX_PHRASE_STR_LEN (MAX_PHRASE_LEN * CH_SZ + 1)
++
++#define Min(a,b) ((a) < (b) ? (a):(b))
++
++#define TSIN_HASH_N (256)
++
++extern char phofname[128];
++extern u_short idxnum_pho;
++extern PHO_IDX *idx_pho;
++extern int ch_pho_ofs;
++extern PHO_ITEM *ch_pho;
++extern int ch_phoN;
++extern PIN_JUYIN *pin_juyin;
++extern int pin_juyinN;
++
++void pho_load();
++extern char *pho_chars[];
++char *phokey_to_str(phokey_t kk);
++int utf8_pho_keys(char *big5, phokey_t *phkeys);
++void prph(phokey_t kk);
++void prphs(phokey_t *ks, int ksN);
++phokey_t pho2key(char typ_pho[]);
++gboolean save_phrase_to_db(void *phkeys, char *utf8str, int len, usecount_t usecount);
++int lookup(u_char *s);
++int find_match(char *str, int *eq_N, usecount_t *usecount);
++char *phokey_to_str2(phokey_t kk, int last_number);
++char *pho_idx_str(int idx);
++char *pho_idx_str2(int idx, int *is_phrase);
++
++
++#define MAX_PH_BF (90)
++
++#define MAX_PH_BF_EXT (MAX_PH_BF + MAX_PHRASE_LEN + 1)
++
++
++#define TSIN_HASH_SHIFT 6
++#define TSIN_HASH_SHIFT_32 24
++#define TSIN_HASH_SHIFT_64 56
++
++#define PHO_CHAR_LEN 3
++
++#define L_BRACKET_NO 22
++#define R_BRACKET_NO 23
++#define BACK_QUOTE_NO 24
++
++#define PHO_PHRASE_ESCAPE 0x1b
++#define PHO_PINYIN_TONE1 -1
+diff --git a/src/plugins/platforminputcontexts/hime/include/tsin-parse.c b/src/plugins/platforminputcontexts/hime/include/tsin-parse.c
+new file mode 100644
+index 0000000..9df67f1
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/tsin-parse.c
+@@ -0,0 +1,353 @@
++/* Copyright (C) 2010 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <string.h>
++#include "hime.h"
++#include "pho.h"
++#include "tsin.h"
++#include "hime-conf.h"
++#include <math.h>
++#include "tsin-parse.h"
++#include "gtab-buf.h"
++#include "gst.h"
++
++#define DBG (0)
++extern gboolean tsin_is_gtab;
++extern int ph_key_sz;
++void add_cache(int start, int usecount, TSIN_PARSE *out, short match_phr_N, short no_match_ch_N, int tc_len);
++void extract_gtab_key(int start, int len, void *out);
++gboolean check_gtab_fixed_mismatch(int idx, char *mtch, int plen);
++void mask_tone(phokey_t *pho, int plen, char *tone_mask);
++
++static int tsin_parse_len;
++
++void set_tsin_parse_len(int len)
++{
++  tsin_parse_len = len;
++}
++
++static char *c_pinyin_set;
++
++int tsin_parse_recur(int start, TSIN_PARSE *out,
++                     short *r_match_phr_N, short *r_no_match_ch_N)
++{
++  int plen;
++  double bestscore = -1;
++  int bestusecount = 0;
++  *r_match_phr_N = 0;
++  *r_no_match_ch_N = tsin_parse_len - start;
++
++
++  for(plen=1; start + plen <= tsin_parse_len && plen <= MAX_PHRASE_LEN; plen++) {
++#if DBG
++    dbg("---- aa st:%d hh plen:%d ", start, plen);utf8_putchar(tss.chpho[start].ch); dbg("\n");
++#endif
++    if (plen > 1) {
++      if (tsin_is_gtab) {
++        if (gbuf[start+plen-1].flag & FLAG_CHPHO_PHRASE_USER_HEAD)
++          break;
++      } else
++        if (tss.chpho[start+plen-1].flag & FLAG_CHPHO_PHRASE_USER_HEAD)
++          break;
++    }
++
++    phokey_t pp[MAX_PHRASE_LEN + 1];
++    u_int pp32[MAX_PHRASE_LEN + 1];
++    u_int64_t pp64[MAX_PHRASE_LEN + 1];
++    int sti, edi;
++    TSIN_PARSE pbest[MAX_PH_BF_EXT+1];
++#define MAXV 1000
++    int maxusecount = 5-MAXV;
++    int remlen;
++    short match_phr_N=0, no_match_ch_N = plen;
++    void *ppp;
++
++    if (ph_key_sz==2)
++      ppp=pp;
++    else if (ph_key_sz==4)
++      ppp=pp32;
++    else
++      ppp=pp64;
++
++    bzero(pbest, sizeof(TSIN_PARSE) * tsin_parse_len);
++
++    pbest[0].len = plen;
++    pbest[0].start = start;
++    int i, ofs;
++
++    if (tsin_is_gtab)
++      for(ofs=i=0; i < plen; i++)
++        ofs += utf8cpy((char *)pbest[0].str + ofs, gbuf[start + i].ch);
++    else
++      for(ofs=i=0; i < plen; i++)
++        ofs += utf8cpy((char *)pbest[0].str + ofs, tss.chpho[start + i].ch);
++
++#if DBG
++    dbg("st:%d hh plen:%d ", start, plen);utf8_putchar(tss.chpho[start].ch); dbg("\n");
++#endif
++
++    if (tsin_is_gtab)
++      extract_gtab_key(start, plen, ppp);
++    else {
++      extract_pho(start, plen, (phokey_t *)ppp);
++      if (c_pinyin_set)
++        mask_tone(pp, plen, c_pinyin_set + start);
++    }
++
++#if DBG
++    for(i=0; i < plen; i++) {
++      prph(pp[i]); dbg("%d", c_pinyin_set[i+start]);
++    }
++    dbg("\n");
++#endif
++
++    char *pinyin_set = c_pinyin_set ? c_pinyin_set+start:NULL;
++    if (!tsin_seek(ppp, plen, &sti, &edi, pinyin_set)) {
++//      dbg("tsin_seek not found...\n");
++      if (plen > 1)
++        break;
++      goto next;
++    }
++
++    phokey_t mtk[MAX_PHRASE_LEN];
++    u_int mtk32[MAX_PHRASE_LEN];
++    u_int64_t mtk64[MAX_PHRASE_LEN];
++    void *pho;
++
++    if (ph_key_sz==2)
++      pho=mtk;
++    else if (ph_key_sz==4)
++      pho=mtk32;
++    else
++      pho=mtk64;
++
++    for (;sti < edi; sti++) {
++      char mtch[MAX_PHRASE_LEN*CH_SZ+1];
++      char match_len;
++      usecount_t usecount;
++
++      load_tsin_entry(sti, &match_len, &usecount, pho, (u_char *)mtch);
++
++      if (match_len < plen)
++        continue;
++
++      if (tsin_is_gtab) {
++        if (check_gtab_fixed_mismatch(start, mtch, plen))
++          continue;
++      } else
++      if (check_fixed_mismatch(start, mtch, plen))
++        continue;
++
++      if (usecount < 0)
++        usecount = 0;
++
++      int i;
++      if (ph_key_sz==2) {
++        if (c_pinyin_set) {
++//          mask_tone(pp, plen, c_pinyin_set + start);
++          mask_tone(mtk, plen, c_pinyin_set + start);
++        }
++        for(i=0;i < plen;i++)
++          if (mtk[i]!=pp[i])
++            break;
++      } else if (ph_key_sz==4) {
++        for(i=0;i < plen;i++)
++          if (mtk32[i]!=pp32[i])
++            break;
++      } else {
++        for(i=0;i < plen;i++)
++          if (mtk64[i]!=pp64[i])
++            break;
++      }
++
++      if (i < plen)
++        continue;
++
++      if (match_len > plen) {
++        continue;
++      }
++
++      if (usecount <= maxusecount)
++        continue;
++
++      pbest[0].len = plen;
++      maxusecount = usecount;
++      utf8cpyN((char *)pbest[0].str, mtch, plen);
++      pbest[0].flag |= FLAG_TSIN_PARSE_PHRASE;
++
++      match_phr_N = 1;
++      no_match_ch_N = 0;
++#if DBG
++      utf8_putcharn(mtch, plen);
++      dbg("   plen %d usecount:%d  ", plen, usecount);
++        utf8_putcharn(mtch, plen);
++      dbg("\n");
++#endif
++    }
++
++
++next:
++
++#if 0
++    if (!match_phr_N) {
++      if (tsin_is_gtab) {
++        if (!(gbuf[start].ch[0] & 0x80))
++          no_match_ch_N = 0;
++      } else
++      if (!(tss.chpho[start].ch[0] & 0x80))
++        no_match_ch_N = 0;
++    }
++#else
++//	dbg("no_match_ch_N %d\n", no_match_ch_N);
++#endif
++
++    remlen = tsin_parse_len - (start + plen);
++
++
++    if (remlen) {
++      int next = start + plen;
++      CACHE *pca;
++
++      short smatch_phr_N, sno_match_ch_N;
++      int uc;
++
++      if ((pca = cache_lookup(next))) {
++        uc = pca->usecount;
++        smatch_phr_N = pca->match_phr_N;
++        sno_match_ch_N = pca->no_match_ch_N;
++        memcpy(&pbest[1], pca->best, (tsin_parse_len - next) * sizeof(TSIN_PARSE));
++      } else {
++        uc = tsin_parse_recur(next, &pbest[1], &smatch_phr_N, &sno_match_ch_N);
++//        dbg("   gg %d\n", smatch_phr_N);
++        add_cache(next, uc, &pbest[1], smatch_phr_N, sno_match_ch_N, tsin_parse_len);
++      }
++
++      match_phr_N += smatch_phr_N;
++      no_match_ch_N += sno_match_ch_N;
++      maxusecount += uc;
++    }
++
++
++    double score = log((double)maxusecount + MAXV) /
++      (pow((double)match_phr_N, 10)+ 1.0E-6) / (pow((double)no_match_ch_N, 20) + 1.0E-6);
++
++#if DBG
++    dbg("st:%d plen:%d zz muse:%d ma:%d noma:%d  score:%.4e %.4e\n", start, plen,
++        maxusecount, match_phr_N, no_match_ch_N, score, bestscore);
++#endif
++    if (score > bestscore) {
++#if DBG
++      dbg("is best org %.4e\n", bestscore);
++#endif
++      bestscore = score;
++      memcpy(out, pbest, sizeof(TSIN_PARSE) * (tsin_parse_len - start));
++
++#if DBG
++      dbg("    str:%d  ", start);
++      int i;
++      for(i=0;  i < tsin_parse_len - start; i++) {
++        utf8_putcharn((char *)out[i].str, out[i].len);
++      }
++      dbg("\n");
++#endif
++
++      bestusecount = maxusecount;
++      *r_match_phr_N = match_phr_N;
++      *r_no_match_ch_N = no_match_ch_N;
++    }
++  }
++
++  if (bestusecount < 0)
++    bestusecount = 0;
++
++  return bestusecount;
++}
++
++void disp_ph_sta_idx(int idx);
++
++void free_cache(), load_tsin_db();
++void tsin_parse()
++{
++  TSIN_PARSE out[MAX_PH_BF_EXT+1];
++  bzero(out, sizeof(out));
++
++  int i, ofsi;
++
++  if (tss.c_len <= 1)
++    return;
++
++  load_tsin_db();
++
++  set_tsin_parse_len(tss.c_len);
++
++  init_cache(tss.c_len);
++
++  char pinyin_set[MAX_PH_BF_EXT];
++  c_pinyin_set = pin_juyin?pinyin_set:NULL;
++  get_chpho_pinyin_set(pinyin_set);
++
++  short smatch_phr_N, sno_match_ch_N;
++  tsin_parse_recur(0, out, &smatch_phr_N, &sno_match_ch_N);
++
++#if 0
++  puts("vvvvvvvvvvvvvvvv");
++  for(i=0;  i < tss.c_len; i++) {
++    printf("%d:", out[i].len);
++    utf8_putcharn(out[i].str, out[i].len);
++  }
++  dbg("\n");
++#endif
++
++  for(i=0; i < tss.c_len; i++)
++    tss.chpho[i].flag &= ~(FLAG_CHPHO_PHRASE_HEAD|FLAG_CHPHO_PHRASE_BODY);
++
++  for(ofsi=i=0; out[i].len; i++) {
++    int j, ofsj;
++    int psta = ofsi;
++
++    if (out[i].flag & FLAG_TSIN_PARSE_PHRASE)
++        tss.chpho[ofsi].flag |= FLAG_CHPHO_PHRASE_HEAD;
++
++    for(ofsj=j=0; j < out[i].len; j++) {
++      ofsj += utf8cpy(tss.chpho[ofsi].cha, (char *)&out[i].str[ofsj]);
++//      tss.chpho[ofsi].ch = tss.chpho[ofsi].cha;
++
++      tss.chpho[ofsi].flag |= FLAG_CHPHO_PHRASE_BODY;
++      if (out[i].flag & FLAG_TSIN_PARSE_PHRASE)
++        tss.chpho[ofsi].psta = psta;
++
++      ofsi++;
++    }
++  }
++
++  int ph_sta_idx = tss.ph_sta;
++  if (tss.chpho[tss.c_len-1].psta>=0 && tss.c_len - tss.chpho[tss.c_len-1].psta > 1) {
++    ph_sta_idx = tss.chpho[tss.c_len-1].psta;
++  }
++
++#if 1
++  disp_ph_sta_idx(ph_sta_idx);
++#endif
++
++#if 0
++  for(i=0;i<tss.c_len;i++)
++    utf8_putchar(tss.chpho[i].ch);
++  puts("");
++#endif
++
++  free_cache();
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/tsin-parse.h b/src/plugins/platforminputcontexts/hime/include/tsin-parse.h
+new file mode 100644
+index 0000000..7f3771b
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/tsin-parse.h
+@@ -0,0 +1,40 @@
++/* Copyright (C) 2010 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++typedef struct {
++  char len, flag;
++  u_char start;
++  unsigned char str[MAX_PHRASE_LEN*CH_SZ+1];  // use malloc
++} TSIN_PARSE;
++
++enum {
++  FLAG_TSIN_PARSE_PHRASE = 1,
++  FLAG_TSIN_PARSE_PARTIAL = 2, //partial phrase
++};
++
++typedef struct {
++  int start;
++  int usecount;
++  short match_phr_N, no_match_ch_N;
++  TSIN_PARSE best[MAX_PH_BF_EXT+1];
++} CACHE;
++
++void tsin_parse();
++void init_cache(int tc_len);
++CACHE *cache_lookup(int start);
++int tsin_parse_recur(int start, TSIN_PARSE *out,
++                     short *r_match_phr_N, short *r_no_match_ch_N);
+diff --git a/src/plugins/platforminputcontexts/hime/include/tsin.c b/src/plugins/platforminputcontexts/hime/include/tsin.c
+new file mode 100644
+index 0000000..aeaae3e
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/tsin.c
+@@ -0,0 +1,2224 @@
++/* Copyright (C) 2004-2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <string.h>
++
++#include "hime.h"
++#include "pho.h"
++#include "tsin.h"
++#include "hime-conf.h"
++#include "tsin-parse.h"
++#include "win-save-phrase.h"
++#include "gst.h"
++#include "gtab.h"
++#include "pho-status.h"
++
++extern int ph_key_sz;
++extern GtkWidget *gwin1;
++gboolean key_press_alt, key_press_ctrl;
++extern gboolean b_hsu_kbm;
++extern gboolean test_mode;
++
++extern char *pho_chars[];
++
++TSIN_ST tss;
++
++gboolean typ_pho_empty();
++void mask_tone(phokey_t *pho, int plen, char *tone_off);
++
++extern u_short hash_pho[];
++extern PHOKBM phkbm;
++
++extern int hashidx[TSIN_HASH_N];
++// gboolean eng_ph=TRUE;  // english(FALSE) <-> pho(juyin, TRUE)
++
++void clrin_pho(), hide_win0();
++void show_tsin_stat();
++void save_CS_current_to_temp();
++
++gboolean tsin_pho_mode()
++{
++  return current_CS && current_CS->tsin_pho_mode;
++}
++
++void set_tsin_pho_mode0(ClientState *cs)
++{
++  if (!cs)
++    return;
++  cs->tsin_pho_mode = 1;
++  save_CS_current_to_temp();
++}
++
++void set_tsin_pho_mode()
++{
++  set_tsin_pho_mode0(current_CS);
++  show_tsin_stat();
++}
++
++gboolean tsin_cursor_end()
++{
++  return tss.c_idx==tss.c_len;
++}
++
++gboolean tsin_has_input();
++static void clrin_pho_tsin()
++{
++  clrin_pho();
++
++  if (!tsin_has_input() && hime_pop_up_win)
++    hide_win0();
++}
++
++gboolean pho_has_input();
++gboolean hime_edit_display_ap_only();
++
++gboolean tsin_has_input()
++{
++  gboolean v = (!hime_edit_display_ap_only() && tss.c_len) || pho_has_input();
++//  dbg("tsin_has_input %d\n", v);
++  return v;
++}
++
++
++void disp_char(int index, char *ch);
++
++static void disp_char_chbuf(int idx)
++{
++//  dbg("disp_char_chbuf %d '%s' '%s'\n", idx, tss.chpho[idx].ch, tss.chpho[idx].cha);
++  disp_char(idx, tss.chpho[idx].ch);
++}
++
++static void init_chpho_i(int i)
++{
++//  dbg("init_chpho_i %d\n", i);
++  tss.chpho[i].ch = tss.chpho[i].cha;
++  tss.chpho[i].ch[0]=' ';
++  tss.chpho[i].ch[1]=0;
++  tss.chpho[i].flag=0;
++  tss.chpho[i].psta=-1;
++}
++
++void clr_tsin_cursor(int index);
++
++static void clrcursor()
++{
++  clr_tsin_cursor(tss.c_idx);
++}
++
++void set_cursor_tsin(int index);
++
++void drawcursor()
++{
++  clr_tsin_cursor(tss.last_cursor_idx);
++  tss.last_cursor_idx = tss.c_idx;
++
++  if (!tss.c_len)
++    return;
++
++  if (tss.c_idx == tss.c_len) {
++    if (!tsin_pho_mode()) {
++      if (tss.tsin_half_full) {
++        disp_char(tss.c_idx,"  ");
++        set_cursor_tsin(tss.c_idx);
++      } else {
++        disp_char(tss.c_idx, " ");
++        set_cursor_tsin(tss.c_idx);
++      }
++    }
++  }
++  else {
++    set_cursor_tsin(tss.c_idx);
++  }
++}
++
++void chpho_extract(CHPHO *chph, int len, phokey_t *pho, char *ch)
++{
++   int i;
++   int ofs=0;
++   ch[0]=0;
++
++   for(i=0; i < len; i++) {
++      if (pho)
++        pho[i] = chph[i].pho;
++
++      char *str = chph[i].ch;
++      strcat(ch + ofs, str);
++      ofs+=strlen(str);
++   }
++//   dbg("chpho_extract %s\n", ch);
++}
++
++// in tsin db, # of phokey = # of character, use this to extract only the first characer
++static void chpho_extract_cha(CHPHO *chph, int len, phokey_t *pho, char *ch)
++{
++   int i;
++   int ofs=0;
++
++   for(i=0; i < len; i++) {
++      if (pho)
++        pho[i] = chph[i].pho;
++      ofs += u8cpy(ch + ofs, chph[i].ch);
++   }
++
++   ch[ofs]=0;
++//   dbg("chpho_extract %s\n", ch);
++}
++
++void chpho_get_str(int idx, int len, char *ch)
++{
++  int ofs=0, i;
++  for(i=0; i < len; i++) {
++	int u8len = u8cpy(&ch[ofs], tss.chpho[idx+i].ch);
++    ofs+=u8len;
++  }
++
++  ch[ofs]=0;
++}
++
++
++void inc_pho_count(phokey_t key, int ch_idx);
++int ch_key_to_ch_pho_idx(phokey_t phkey, char *big5);
++void inc_dec_tsin_use_count(void *pho, char *ch, int prlen);
++void lookup_gtabn(char *ch, char *);
++
++static void putbuf(int len)
++{
++  u_char tt[CH_SZ * (MAX_PH_BF_EXT+1) + 1];
++  int i,idx;
++
++//  dbg("putbuf:%d\n", len);
++#if 1
++  // update phrase reference count
++  if (len >= 2) {
++    for(i=0; i < len; i++) {
++//      dbg("flag %d %x\n", i, tss.chpho[i].flag);
++      if (!BITON(tss.chpho[i].flag, FLAG_CHPHO_PHRASE_HEAD)) {
++        continue;
++      }
++
++      int j;
++      for(j=i+1; j < len; j++)
++        if (tss.chpho[j].psta != i)
++          break;
++
++      int phrlen = j - i;
++      if (phrlen < 1)
++        continue;
++
++      phokey_t pho[MAX_PHRASE_LEN];
++      char ch[MAX_PHRASE_LEN * CH_SZ * 2];
++
++      chpho_extract(&tss.chpho[i], phrlen, pho, ch);
++
++      inc_dec_tsin_use_count(pho, ch, phrlen);
++    }
++  }
++#endif
++
++  for(idx=i=0;i<len;i++) {
++#if 0
++    int len = utf8_sz(tss.chpho[i].ch);
++#else
++    int len = strlen(tss.chpho[i].ch);
++#endif
++
++    if (tss.chpho[i].pho && len > 1) {
++      int pho_idx = ch_key_to_ch_pho_idx(tss.chpho[i].pho, tss.chpho[i].ch);
++      if (pho_idx >= 0)
++        inc_pho_count(tss.chpho[i].pho, pho_idx);
++    }
++
++    memcpy(&tt[idx], tss.chpho[i].ch, len);
++    idx += len;
++  }
++
++  tt[idx]=0;
++  send_text((char *)tt);
++  lookup_gtabn((char *)tt, NULL);
++}
++
++
++void hide_char(int index);
++
++static void prbuf()
++{
++  int i;
++
++//  dbg("prbuf\n");
++  for(i=0;i<tss.c_len;i++)
++	if (!(tss.chpho[i].flag & FLAG_CHPHO_PHO_PHRASE))
++		tss.chpho[i].ch=tss.chpho[i].cha;
++
++  for(i=0; i < tss.c_len; i++)
++    disp_char_chbuf(i);
++
++  for(i=tss.c_len; i < MAX_PH_BF_EXT; i++) {
++    hide_char(i);
++  }
++
++  drawcursor();
++}
++
++
++void disp_tsin_pho(int index, char *pho);
++
++static void disp_in_area_pho_tsin()
++{
++  int i;
++
++  if (pin_juyin) {
++    for(i=0;i<6;i++) {
++      disp_tsin_pho(i, &poo.inph[i]);
++    }
++  } else {
++    for(i=0;i<4;i++) {
++      if (poo.typ_pho[0]==BACK_QUOTE_NO && i==1)
++        break;
++      disp_tsin_pho(i, &pho_chars[i][poo.typ_pho[i] * PHO_CHAR_LEN]);
++    }
++  }
++}
++
++static int get_in_area_pho_tsin_str(char *out)
++{
++  int i;
++  int outN=0;
++
++  if (pin_juyin) {
++    for(i=0;i<6;i++)
++      if (poo.inph[i])
++        out[outN++] = poo.inph[i];
++  } else {
++    for(i=0;i<4;i++)
++      if (poo.typ_pho[i]) {
++        outN+=u8cpy(out+outN, &pho_chars[i][poo.typ_pho[i] * PHO_CHAR_LEN]);
++      }
++  }
++
++  out[outN]=0;
++  return outN;
++}
++
++void clear_chars_all();
++
++static void clear_match()
++{
++  tss.ph_sta=-1;
++}
++
++static void clr_ch_buf()
++{
++  int i;
++  for(i=0; i < MAX_PH_BF_EXT; i++) {
++    init_chpho_i(i);
++  }
++
++  clear_match();
++}
++
++
++static void clear_ch_buf_sel_area()
++{
++  clear_chars_all();
++  tss.c_len=tss.c_idx=0; tss.ph_sta=-1;
++  tss.full_match = FALSE;
++  clr_ch_buf();
++  drawcursor();
++}
++
++static void close_selection_win();
++
++static void clear_tsin_buffer()
++{
++  clear_ch_buf_sel_area();
++  close_selection_win();
++  tss.pre_selN = 0;
++  tss.tsin_buffer_editing = 0; //buffer editing is finished
++}
++
++void clr_in_area_pho_tsin();
++void close_win_pho_near();
++void compact_win0();
++
++#if USE_TSIN
++void tsin_reset_in_pho0()
++{
++//  prbuf();
++  clr_in_area_pho_tsin();
++  close_selection_win();
++  tss.pre_selN = 0;
++//  tss.pho_menu_idx = 0;
++  drawcursor();
++  close_win_pho_near();
++}
++#endif
++
++
++#if USE_TSIN
++void tsin_reset_in_pho()
++{
++  clrin_pho_tsin();
++  tsin_reset_in_pho0();
++}
++#endif
++
++
++void flush_tsin_buffer()
++{
++  tsin_reset_in_pho();
++
++  if (hime_pop_up_win)
++    hide_win0();
++
++  if (tss.c_len) {
++    putbuf(tss.c_len);
++    compact_win0();
++    clear_ch_buf_sel_area();
++    clear_tsin_buffer();
++    return;
++  }
++
++  return;
++}
++
++
++void disp_tsin_eng_pho(int eng_pho);
++#if TRAY_ENABLED
++void disp_tray_icon();
++#endif
++
++void show_tsin_stat()
++{
++#if TRAY_ENABLED
++  disp_tray_icon();
++#endif
++  disp_tsin_eng_pho(tsin_pho_mode());
++}
++
++void load_tsin_db();
++
++#if 0
++void nputs(u_char *s, u_char len)
++{
++  char tt[16];
++
++  memcpy(tt, s, len*CH_SZ);
++  tt[len*CH_SZ]=0;
++  dbg("%s", tt);
++}
++
++
++static void dump_tsidx(int i)
++{
++  phokey_t pho[MAX_PHRASE_LEN];
++  u_char ch[MAX_PHRASE_LEN*CH_SZ];
++  usecount_t usecount;
++  u_char len;
++
++  load_tsin_entry(i, &len, &usecount, pho, ch);
++
++  int j;
++  for(j=0; j < len; j++) {
++    prph(pho[j]);
++    dbg(" ");
++  }
++
++  nputs(ch, len);
++  dbg("\n");
++}
++
++
++static void dump_tsidx_all()
++{
++  int i;
++
++  for(i=0; i < phcount; i++) {
++    dump_tsidx(i);
++  }
++
++  dbg("************************************************\n");
++  for(i=0; i < 254; i++) {
++    dbg("%d]%d ", i, hashidx[i]);
++    dump_tsidx(hashidx[i]);
++  }
++}
++
++#endif
++
++void load_tab_pho_file();
++void show_win0();
++
++void init_pre_sel()
++{
++  if (!tss.pre_sel)
++    tss.pre_sel=tzmalloc(PRE_SEL, 10);
++}
++
++void init_tab_pp(gboolean init)
++{
++  if (!tss.chpho)
++    tss.chpho=tzmalloc(CHPHO, MAX_PH_BF_EXT);
++
++//  tss.ph_sta_last = -1;
++
++  init_pre_sel();
++
++  if (!ch_pho)
++    load_tab_pho_file();
++
++  load_tsin_db();
++
++  if (init)
++    clr_ch_buf();
++
++  show_tsin_stat();
++  if (init)
++    clear_ch_buf_sel_area();
++
++  if (!hime_pop_up_win)
++    show_win0();
++}
++
++
++static void move_cursor_end()
++{
++  clrcursor();
++  tss.c_idx=tss.c_len;
++  drawcursor();
++}
++
++gboolean save_phrase_to_db2(CHPHO *chph, int len);
++
++void save_phrase(int save_frm, int len)
++{
++  int save_to = save_frm + len -1;
++  if (len <= 0 || len > MAX_PHRASE_LEN)
++    return;
++
++  int i;
++  for(i=save_frm;i<=save_to;i++) {
++    if (tss.chpho[i].pho)
++      continue;
++    phokey_t tpho[32];
++    tpho[0]=0;
++
++    utf8_pho_keys(tss.chpho[i].ch, tpho);
++
++    if (!tpho[0])
++      return;
++
++    tss.chpho[i].pho = tpho[0];
++  }
++
++  if (!save_phrase_to_db2(&tss.chpho[save_frm], len)) {
++    bell();
++  }
++
++  tss.ph_sta=-1;
++  move_cursor_end();
++  return;
++}
++
++
++static void set_fixed(int idx, int len)
++{
++  int i;
++  for(i=idx; i < idx+len; i++) {
++    tss.chpho[i].flag |= FLAG_CHPHO_FIXED;
++    tss.chpho[i].flag &= ~FLAG_CHPHO_PHRASE_USER_HEAD;
++  }
++}
++
++#define PH_SHIFT_N (tsin_buffer_size - 1)
++
++static void shift_ins()
++{
++   int j;
++//   dbg("shift_ins()\n");
++
++   if (!tss.c_idx && tss.c_len >= PH_SHIFT_N) {
++     tss.c_len--;
++   }
++   else
++   if (tss.c_len >= PH_SHIFT_N) {
++     int ofs;
++
++     // set it fixed so that it will not cause partial phrase in the beginning
++     int fixedlen = tss.c_len - 10;
++     if (fixedlen <= 0)
++       fixedlen = 1;
++     set_fixed(0, fixedlen);
++
++     ofs = 1;
++     putbuf(ofs);
++
++     tss.ph_sta-=ofs;
++     for(j=0; j < tss.c_len - ofs; j++) {
++       tss.chpho[j] = tss.chpho[j+ofs];
++#if 0
++	   if (!(tss.chpho[j].flag & FLAG_CHPHO_PHO_PHRASE))
++		 tss.chpho[j].ch = tss.chpho[j].cha;
++#endif
++     }
++     tss.c_idx-=ofs;
++     tss.c_len-=ofs;
++     prbuf();
++   }
++
++
++   init_chpho_i(tss.c_len);
++
++   if (tss.c_idx < tss.c_len) {
++     for(j=tss.c_len-1; j>=tss.c_idx; j--) {
++       tss.chpho[j+1] = tss.chpho[j];
++#if 0
++	   if (!(tss.chpho[j+1].flag & FLAG_CHPHO_PHO_PHRASE)) {
++		 tss.chpho[j+1].ch = tss.chpho[j+1].cha;
++//		 dbg("copy %d %s\n", j+1, tss.chpho[j+1].ch);
++	   }
++#endif
++     }
++   }
++
++   tss.c_len++;
++   compact_win0();
++
++#if 0
++   prbuf();
++   dbg("leave shift_ins\n");
++#endif
++}
++
++
++static void put_u8_char(int pho_idx, phokey_t key, gboolean b_tone)
++{
++   shift_ins();
++   int is_phrase;
++   char *str = pho_idx_str2(pho_idx, &is_phrase);
++
++   init_chpho_i(tss.c_idx);
++
++//   dbg("put_b5_char %d] %d\n", tss.c_idx, b_tone);
++
++   if (is_phrase) {
++     dbg("is_phrase %s\n", str);
++     tss.chpho[tss.c_idx].ch = str;
++     tss.chpho[tss.c_idx].flag |= FLAG_CHPHO_PHO_PHRASE;
++   }
++   else {
++     bzero(tss.chpho[tss.c_idx].cha, sizeof(tss.chpho[0].cha));
++     bchcpy(tss.chpho[tss.c_idx].cha, str);
++     tss.chpho[tss.c_idx].ch = tss.chpho[tss.c_idx].cha;
++//     dbg("wwww %s\n",tss.chpho[tss.c_idx].ch);
++   }
++
++   if (b_tone)
++     tss.chpho[tss.c_idx].flag |= FLAG_CHPHO_PINYIN_TONE;
++
++   disp_char_chbuf(tss.c_idx);
++
++   tss.chpho[tss.c_idx].pho=key;
++   tss.c_idx++;
++
++#if 0
++   if (tss.c_idx < tss.c_len) {
++     prbuf();
++   }
++#endif
++}
++
++
++#define MAX_PHRASE_SEL_N 10
++
++static u_char selstr[MAX_PHRASE_SEL_N][MAX_PHRASE_LEN * CH_SZ];
++static u_char sellen[MAX_PHRASE_SEL_N];
++
++static u_short phrase_count;
++static u_short pho_count;
++
++static gboolean chpho_eq_pho(int idx, phokey_t *phos, int len)
++{
++  int i;
++
++  for(i=0; i < len; i++)
++    if (tss.chpho[idx+i].pho != phos[i])
++       return FALSE;
++
++  return TRUE;
++}
++
++
++char *get_chpho_pinyin_set(char *set_arr)
++{
++  if (!pin_juyin)
++    return NULL;
++  int i;
++  for(i=0; i < tss.c_len; i++) {
++    if (tss.chpho[i].flag & FLAG_CHPHO_PINYIN_TONE)
++      set_arr[i]=TRUE;
++    else
++      set_arr[i]=FALSE;
++
++//    dbg("pin %d] %d\n", i, set_arr[i]);
++  }
++  return set_arr;
++}
++
++
++static void get_sel_phrase0(int selidx, gboolean eqlen)
++{
++  int sti,edi;
++  u_char len, mlen;
++
++  mlen=tss.c_len-selidx;
++
++  if (!mlen)
++    return;
++
++  if (mlen > MAX_PHRASE_LEN)
++    mlen=MAX_PHRASE_LEN;
++
++  phokey_t pp[MAX_PHRASE_LEN + 1];
++  extract_pho(selidx, mlen, pp);
++
++  char *pinyin_s = NULL;
++  char pinyin_set[MAX_PH_BF_EXT];
++
++  if (pin_juyin)
++    pinyin_s = get_chpho_pinyin_set(pinyin_set) + selidx;
++
++  if (!tsin_seek(pp, 2, &sti, &edi, pinyin_s))
++    return;
++
++  while (sti < edi && phrase_count < phkbm.selkeyN) {
++    phokey_t stk[MAX_PHRASE_LEN];
++    usecount_t usecount;
++    u_char stch[MAX_PHRASE_LEN * CH_SZ + 1];
++
++    load_tsin_entry(sti, (char *)&len, &usecount, stk, stch);
++    mask_tone(stk, mlen, pinyin_s);
++
++    if ((eqlen && len!=mlen) || (!eqlen && len > mlen) || len==1) {
++      sti++;
++      continue;
++    }
++
++    if (chpho_eq_pho(selidx, stk, len)) {
++      sellen[phrase_count]=len;
++      utf8cpyN((char *)selstr[phrase_count++], (char *)stch, len);
++    }
++
++    sti++;
++  }
++}
++
++static void get_sel_phrase_end()
++{
++  int stidx = tss.c_idx - 5;
++  if (stidx < 0)
++    stidx = 0;
++
++  phrase_count = 0;
++  int i;
++  for(i=stidx; i < tss.c_len - 1; i++) {
++    get_sel_phrase0(i, TRUE);
++  }
++}
++
++static void get_sel_phrase()
++{
++  phrase_count = 0;
++  get_sel_phrase0(tss.c_idx, FALSE);
++}
++
++static void get_sel_pho()
++{
++  int idx = tss.c_idx==tss.c_len?tss.c_idx-1:tss.c_idx;
++  phokey_t key = tss.chpho[idx].pho;
++
++  if (!key)
++    return;
++
++  char need_mask = pin_juyin && !(tss.chpho[idx].flag & FLAG_CHPHO_PINYIN_TONE);
++//  dbg("need_mask %d\n", need_mask);
++
++  int i=hash_pho[key>>9];
++  phokey_t ttt;
++
++  while (i<idxnum_pho) {
++    ttt=idx_pho[i].key;
++    if (need_mask)
++      ttt &= ~7;
++
++    if (ttt>=key)
++      break;
++    i++;
++  }
++
++  if (ttt!=key) {
++    return;
++  }
++
++  tss.startf = idx_pho[i].start;
++  int end;
++
++  if (need_mask) {
++    while (i<idxnum_pho) {
++      ttt=idx_pho[i].key;
++
++      if (need_mask)
++        ttt &= ~7;
++
++      if (ttt>key)
++        break;
++      i++;
++    }
++    end = idx_pho[i].start;
++//    dbg("end %d\n", i);
++  } else
++    end = idx_pho[i+1].start;
++
++  pho_count = end - tss.startf;
++//  dbg("pho_count %d\n", pho_count);
++}
++
++
++void clear_sele();
++void set_sele_text(int tN, int i, char *text, int len);
++void disp_arrow_up(), disp_arrow_down();
++void disp_tsin_select(int index);
++
++static void disp_current_sel_page()
++{
++  int i;
++
++  clear_sele();
++
++  for(i=0; i < phkbm.selkeyN; i++) {
++    int idx = tss.current_page + i;
++
++    if (idx < phrase_count) {
++      int tlen = utf8_tlen((char *)selstr[i], sellen[i]);
++      set_sele_text(phrase_count + pho_count, i, (char *)selstr[i], tlen);
++    } else
++    if (idx < phrase_count + pho_count) {
++      int v = idx - phrase_count + tss.startf;
++      char *tstr = pho_idx_str(v);
++      set_sele_text(phrase_count + pho_count, i, tstr, -1);
++    } else
++      break;
++  }
++
++  if (tss.current_page + phkbm.selkeyN < phrase_count + pho_count) {
++    disp_arrow_down();
++  }
++
++  if (tss.current_page > 0)
++    disp_arrow_up();
++
++  disp_tsin_select(tss.c_idx==tss.c_len?tss.c_idx-1:tss.c_idx);
++}
++
++static int fetch_user_selection(int val, char **seltext, int *is_pho_phrase)
++{
++  int idx = tss.current_page + val;
++  int len = 0;
++
++  *is_pho_phrase = FALSE;
++  if (idx < phrase_count) {
++    len = sellen[idx];
++    *seltext = (char *)selstr[idx];
++  } else
++  if (idx < phrase_count + pho_count) {
++    int v = idx - phrase_count + tss.startf;
++    *seltext = pho_idx_str2(v, is_pho_phrase);
++    len = utf8_str_N(*seltext);
++  }
++
++  return len;
++}
++
++
++void extract_pho(int chpho_idx, int plen, phokey_t *pho)
++{
++  int i;
++
++  for(i=0; i < plen; i++) {
++    pho[i] = tss.chpho[chpho_idx + i].pho;
++  }
++}
++
++
++gboolean check_fixed_mismatch(int chpho_idx, char *mtch, int plen)
++{
++  int j;
++  char *p = mtch;
++
++  for(j=0; j < plen; j++) {
++    int u8sz = utf8_sz(p);
++    if (!(tss.chpho[chpho_idx+j].flag & FLAG_CHPHO_FIXED))
++      continue;
++
++    if (memcmp(tss.chpho[chpho_idx+j].ch, p, u8sz))
++      return TRUE;
++
++    p+= u8sz;
++  }
++
++  return FALSE;
++}
++
++#if 0
++static u_char scanphr(int chpho_idx, int plen, gboolean pho_incr)
++{
++  return scanphr_e(chpho_idx, plen, pho_incr, NULL);
++}
++#endif
++
++void hide_selections_win();
++
++void disp_pre_sel_page()
++{
++  int i;
++
++  if (!tsin_phrase_pre_select) {
++    return;
++  }
++
++  if (!tss.pre_selN)
++    return;
++
++  clear_sele();
++
++  for(i=0; i < tss.pre_selN; i++) {
++    int tlen = utf8_tlen(tss.pre_sel[i].str, tss.pre_sel[i].len);
++
++    set_sele_text(tss.pre_selN, i, tss.pre_sel[i].str, tlen);
++  }
++
++#if 0
++  dbg("tss.ph_sta:%d\n", tss.ph_sta);
++#endif
++  disp_tsin_select(tss.ph_sta);
++}
++
++static void close_selection_win()
++{
++  hide_selections_win();
++  tss.current_page=tss.sel_pho=tss.ctrl_pre_sel = 0;
++  tss.pre_selN = 0;
++}
++
++void show_button_pho(gboolean bshow);
++
++void show_win_gtab();
++void tsin_set_eng_ch(int nmod)
++{
++//  dbg("tsin_set_eng_ch %d\n", nmod);
++  if (current_CS) {
++    current_CS->tsin_pho_mode = nmod;
++    save_CS_current_to_temp();
++  }
++
++  if (current_method_type()==method_type_TSIN) {
++    show_tsin_stat();
++    drawcursor();
++
++    if (!tsin_pho_mode())
++      clrin_pho_tsin();
++
++    show_button_pho(tsin_pho_mode());
++  }
++  else
++    show_win_gtab();
++
++  show_tsin_stat();
++}
++
++void tsin_toggle_eng_ch()
++{
++//  dbg("tsin_toggle_eng_ch\n");
++  compact_win0();
++  tsin_set_eng_ch(!tsin_pho_mode());
++}
++
++
++#if USE_TSIN
++void tsin_toggle_half_full()
++{
++    tss.tsin_half_full^=1;
++    key_press_alt = FALSE;
++    drawcursor();
++#if TRAY_ENABLED
++    disp_tray_icon();
++#endif
++}
++#endif
++
++
++#if 0
++static char ochars[]="<,>.?/:;\"'{[}]_-+=|\\~`";
++#else
++static char ochars[]="<,>.?/:;\"'{[}]_-+=|\\";
++#endif
++
++void hide_pre_sel()
++{
++  tss.pre_selN = 0;
++  hide_selections_win();
++}
++
++
++static void call_tsin_parse()
++{
++  prbuf();
++  tsin_parse();
++  prbuf();
++}
++
++void disp_ph_sta_idx(int idx)
++{
++}
++
++void disp_ph_sta()
++{
++  disp_ph_sta_idx(tss.ph_sta);
++}
++
++void ch_pho_cpy(CHPHO *pchpho, char *utf8, phokey_t *phos, int len)
++{
++  int i;
++
++  for(i=0; i < len; i++) {
++    int len = utf8cpy(pchpho[i].cha, utf8);
++    utf8+=len;
++    pchpho[i].pho = phos[i];
++	pchpho[i].flag &= ~FLAG_CHPHO_PHO_PHRASE;
++  }
++}
++
++
++void set_chpho_ch(CHPHO *pchpho, char *utf8, int len, gboolean is_pho_phrase)
++{
++  int i;
++
++  for(i=0; i < len; i++) {
++    int u8len;
++    if (is_pho_phrase) {
++      pchpho[i].ch = utf8;
++	  pchpho[i].flag |= FLAG_CHPHO_PHO_PHRASE;
++	} else {
++      u8len = utf8cpy(pchpho[i].cha, utf8);
++      pchpho[i].ch = pchpho[i].cha;
++	  pchpho[i].flag &= ~FLAG_CHPHO_PHO_PHRASE;
++    }
++
++    utf8+=u8len;
++  }
++}
++
++
++gboolean add_to_tsin_buf(char *str, phokey_t *pho, int len)
++{
++    int i;
++
++    if (tss.c_idx < 0 || tss.c_len + len >= MAX_PH_BF_EXT)
++      return 0;
++
++    if (tss.c_idx < tss.c_len) {
++      for(i=tss.c_len-1; i >= tss.c_idx; i--) {
++        tss.chpho[i+len] = tss.chpho[i];
++      }
++    }
++
++    ch_pho_cpy(&tss.chpho[tss.c_idx], str, pho, len);
++
++    if (tss.c_idx == tss.c_len)
++      tss.c_idx +=len;
++
++    tss.c_len+=len;
++
++    clrin_pho_tsin();
++    disp_in_area_pho_tsin();
++
++    prbuf();
++
++    set_fixed(tss.c_idx, len);
++#if 1
++    for(i=1;i < len; i++) {
++      tss.chpho[tss.c_idx+i].psta= tss.c_idx;
++    }
++#endif
++#if 0
++    if (len > 0)
++      tss.chpho[tss.c_idx].flag |= FLAG_CHPHO_PHRASE_HEAD;
++#endif
++    drawcursor();
++    disp_ph_sta();
++    hide_pre_sel();
++    tss.ph_sta=-1;
++
++    if (hime_pop_up_win)
++      show_win0();
++
++    return TRUE;
++}
++
++#if 1
++static void set_phrase_link(int idx, int len)
++{
++    int j;
++
++    if (len < 1)
++      return;
++
++    for(j=1;j < len; j++) {
++      tss.chpho[idx+j].psta=idx;
++    }
++
++    tss.chpho[idx].flag |= FLAG_CHPHO_PHRASE_HEAD;
++}
++#endif
++
++
++// should be used only if it is a real phrase
++gboolean add_to_tsin_buf_phsta(char *str, phokey_t *pho, int len)
++{
++    int idx = tss.ph_sta;
++#if 0
++    dbg("idx:%d  tss.ph_sta:%d tss.ph_sta_last:%d tss.c_idx:%d  tss.c_len:%d\n",
++       idx, tss.ph_sta, tss.ph_sta_last, tss.c_idx, tss.c_len);
++#endif
++    if (idx < 0)
++      return 0;
++
++    if (idx + len >= MAX_PH_BF_EXT)
++      flush_tsin_buffer();
++
++    if (tss.c_idx < tss.c_len) {
++      int avlen = tss.c_idx - tss.ph_sta;
++//      dbg("avlen:%d %d\n", avlen, len);
++      if (avlen < len) {
++        int d = len - avlen;
++
++        memmove(&tss.chpho[tss.c_idx + d], &tss.chpho[tss.c_idx], sizeof(CHPHO) * (tss.c_len - tss.c_idx));
++        tss.c_len += d;
++      }
++    } else
++      tss.c_len = idx + len;
++
++    ch_pho_cpy(&tss.chpho[idx], str, pho, len);
++    set_chpho_ch(&tss.chpho[idx], str, len, FALSE);
++    set_fixed(idx, len);
++    tss.chpho[idx].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
++    tss.c_idx=idx + len;
++    tss.chpho[tss.c_idx - 1].flag |= FLAG_CHPHO_PHRASE_TAIL;
++
++    clrin_pho_tsin();
++    disp_in_area_pho_tsin();
++
++    prbuf();
++#if 1
++    set_phrase_link(idx, len);
++#endif
++    drawcursor();
++    disp_ph_sta();
++    hide_pre_sel();
++    tss.ph_sta=-1;
++    call_tsin_parse();
++
++    return 1;
++}
++
++
++void add_to_tsin_buf_str(char *str)
++{
++  char *pp = str;
++  char *endp = pp+strlen(pp);
++  int N = 0;
++
++
++  while (*pp) {
++    int u8sz = utf8_sz(pp);
++    N++;
++    pp += u8sz;
++
++    if (pp >= endp) // bad utf8 string
++      break;
++  }
++
++  dbg("add_to_tsin_buf_str %s %d\n",str, N);
++
++  phokey_t pho[MAX_PHRASE_LEN];
++  bzero(pho, sizeof(pho));
++  add_to_tsin_buf(str, pho, N);
++}
++
++int tsin_pho_sel(int c);
++
++int tsin_sele_by_idx(int c)
++{
++  if (tss.sel_pho) {
++    tsin_pho_sel(c);
++    return 0;
++  }
++
++  int len = tss.pre_sel[c].len;
++
++#if 0
++    dbg("eqlenN:%d %d\n", c, tss.pre_selN);
++#endif
++
++  if (c >= tss.pre_selN)
++    return 0;
++
++  tss.full_match = FALSE;
++  gboolean b_added = add_to_tsin_buf_phsta(tss.pre_sel[c].str, (phokey_t*)tss.pre_sel[c].phkey, len);
++
++  return b_added;
++}
++
++static char shift_sele[]="!@#$%^&*()asdfghjkl:zxcvbnm<>?qwertyuiop";
++static char noshi_sele[]="1234567890asdfghjkl;zxcvbnm,./qwertyuiop";
++int shift_key_idx(char *s, KeySym xkey)
++{
++  if (xkey >= 0x7f)
++    return -1;
++
++  if (isupper(xkey))
++    xkey = xkey - 'A' + 'a';
++
++//  dbg("pre_sel_handler aa\n");
++
++  char *p;
++  if (!(p=strchr(shift_sele, xkey)))
++    return -1;
++
++  int c = p - shift_sele;
++  char noshi = noshi_sele[c];
++
++  if (!(p=strchr(s, noshi)))
++    return -1;
++
++  c = p - s;
++  return c;
++}
++
++
++static gboolean pre_sel_handler(KeySym xkey)
++{
++  if (!tss.pre_selN || !tsin_phrase_pre_select)
++    return FALSE;
++
++  int c = shift_key_idx(pho_selkey, xkey);
++  if (c < 0) {
++    close_selection_win();
++    return FALSE;
++  }
++  return tsin_sele_by_idx(c);
++}
++
++static gboolean pre_punctuation_sub(KeySym xkey, char shift_punc[], unich_t *chars[])
++{
++  char *p;
++  if (xkey > 0x7e)
++    return FALSE;
++
++  if ((p=strchr(shift_punc, xkey))) {
++    int c = p - shift_punc;
++    char *pchar = _(chars[c]);
++
++    if (current_method_type() == method_type_PHO) {
++      char tt[CH_SZ+1];
++      utf8cpy(tt, pchar);
++      send_text(tt);
++    } else {
++      phokey_t keys[64];
++      keys[0]=0;
++      utf8_pho_keys(pchar, keys);
++      add_to_tsin_buf(pchar, &keys[0], 1);
++      if (hime_punc_auto_send && tsin_cursor_end())
++        flush_tsin_buffer();
++    }
++    return 1;
++  }
++
++  return 0;
++}
++
++
++gboolean pre_punctuation(KeySym xkey)
++{
++  static char shift_punc[]="<>?:\"{}!_()";
++  static unich_t *chars[] = { ",", "。", "?", ":", ";", "「", "」", "!", "——", "(", ")" };
++  return pre_punctuation_sub(xkey, shift_punc, chars);
++}
++
++static char hsu_punc[]=",./;'";
++gboolean pre_punctuation_hsu(KeySym xkey)
++{
++  static unich_t *chars[] = { ",", "。", "?", ";", "、" };
++  return pre_punctuation_sub(xkey, hsu_punc, chars);
++}
++
++
++int inph_typ_pho(KeySym newkey);
++
++KeySym keypad_proc(KeySym xkey)
++{
++  if (xkey <= XK_KP_9 && xkey >= XK_KP_0)
++    xkey=xkey-XK_KP_0+'0';
++  else {
++    switch (xkey) {
++      case XK_KP_Add:
++        xkey = '+';
++        break;
++      case XK_KP_Subtract:
++        xkey = '-';
++        break;
++      case XK_KP_Multiply:
++        xkey = '*';
++        break;
++      case XK_KP_Divide:
++        xkey = '/';
++        break;
++      case XK_KP_Decimal:
++        xkey = '.';
++        break;
++      default:
++        return 0;
++    }
++  }
++
++  return xkey;
++}
++
++static int cursor_left()
++{
++//  dbg("cursor left %d %d\n", tss.c_idx, tss.c_len);
++  close_selection_win();
++  if (tss.c_idx) {
++    clrcursor();
++    tss.c_idx--;
++    drawcursor();
++    return 1;
++  }
++  // Thanks to PCMan.bbs@bbs.sayya.org for the suggestion
++  return tss.c_len;
++}
++static int cursor_right()
++{
++//  dbg("cursor right %d %d\n", tss.c_idx, tss.c_len);
++  close_selection_win();
++  if (tss.c_idx < tss.c_len) {
++    clrcursor();
++    tss.c_idx++;
++    drawcursor();
++    return 1;
++  }
++
++  return tss.c_len;
++}
++
++void tsin_scan_pre_select(gboolean b_incr);
++
++static int cursor_backspace()
++{
++        close_selection_win();
++        poo.ityp3_pho=0;
++        tss.pre_selN = 0;
++        gboolean pho_cleared;
++        pho_cleared=FALSE;
++		int j;
++
++        if (pin_juyin) {
++          for(j=sizeof(poo.inph)-1;j>=0;j--) {
++            if (poo.inph[j]) {
++              poo.inph[j]=0;
++              pho_cleared = TRUE;
++			  if (j==0)
++				clrin_pho();
++              break;
++            }
++          }
++        } else {
++          for(j=3;j>=0;j--)
++            if (poo.typ_pho[j]) {
++              poo.typ_pho[j]=0;
++              poo.inph[j]=0;
++              pho_cleared = TRUE;
++              break;
++            }
++        }
++
++        if (pho_cleared) {
++//          dbg("pho cleared %d %d %d\n",tss.c_len, hime_pop_up_win, typ_pho_empty());
++		  if (typ_pho_empty())
++			  bzero(poo.inph, sizeof(poo.inph));
++
++          disp_in_area_pho_tsin();
++          tsin_scan_pre_select(TRUE);
++
++          if (!tss.c_len && hime_pop_up_win && typ_pho_empty())
++            hide_win0();
++          return 1;
++        }
++
++        if (!tss.c_idx)
++          return 0;
++
++        clrcursor();
++        tss.c_idx--;
++//        pst=k=tss.chpho[tss.c_idx].psta;
++
++		int k;
++        for(k=tss.c_idx;k<tss.c_len;k++) {
++          tss.chpho[k]=tss.chpho[k+1];
++          if (tss.chpho[k+1].ch == tss.chpho[k+1].cha)
++            tss.chpho[k].ch = tss.chpho[k].cha;
++        }
++
++        tss.c_len--;
++        init_chpho_i(tss.c_len);
++		call_tsin_parse();
++		compact_win0();
++
++        if (!tss.c_idx) {
++          clear_match();
++        } else {
++          tsin_scan_pre_select(TRUE);
++        }
++
++        disp_ph_sta();
++
++        if (!tss.c_len && hime_pop_up_win)
++          hide_win0();
++
++        return 1;
++}
++
++
++static int cursor_delete()
++{
++	if (tss.c_idx>=tss.c_len)
++		return FALSE;
++	tss.c_idx++;
++	return cursor_backspace();
++}
++
++void case_inverse(KeySym *xkey, int shift_m);
++void pho_play(phokey_t key);
++
++int tsin_pho_sel(int c)
++{
++  char *sel_text;
++  int is_pho_phrase;
++  int len = fetch_user_selection(c, &sel_text, &is_pho_phrase);
++  int sel_idx = tss.c_idx;
++  if (tss.c_idx == tss.c_len)
++    sel_idx = tss.c_len - len;
++
++  set_chpho_ch(&tss.chpho[sel_idx], sel_text, len, is_pho_phrase);
++
++  set_fixed(sel_idx, len);
++
++  call_tsin_parse();
++
++  if (tss.c_idx + len == tss.c_len) {
++    tss.ph_sta = -1;
++//    draw_ul(tss.c_idx, tss.c_len);
++  }
++
++  if (len) {
++    prbuf();
++    tss.current_page=tss.sel_pho=poo.ityp3_pho=0;
++    if (len == 1) {
++      hide_selections_win();
++      tss.ph_sta = -1;
++      return 0;
++    }
++    else
++      tss.ph_sta=-1;
++
++    hide_selections_win();
++  }
++
++  return 1;
++}
++
++
++gboolean tsin_page_up()
++{
++  if (!tss.sel_pho)
++    return tss.c_len;
++
++  tss.current_page = tss.current_page - phkbm.selkeyN;
++  if (tss.current_page < 0)
++    tss.current_page = 0;
++
++  tss.pho_menu_idx = 0;
++  disp_current_sel_page();
++  return TRUE;
++}
++
++gboolean tsin_page_down()
++{
++  if (!tss.sel_pho)
++    return tss.c_len;
++
++  tss.pho_menu_idx = 0;
++  tss.current_page = tss.current_page + phkbm.selkeyN;
++  if (tss.current_page >= phrase_count + pho_count)
++    tss.current_page = 0;
++
++  disp_current_sel_page();
++
++  return TRUE;
++}
++
++void open_select_pho()
++{
++  if (tss.c_idx==tss.c_len) {
++    get_sel_phrase_end();
++  } else
++    get_sel_phrase();
++
++  get_sel_pho();
++  tss.sel_pho=1;
++  tss.pho_menu_idx = tss.current_page = 0;
++  disp_current_sel_page();
++}
++
++gboolean win_sym_page_up(), win_sym_page_down();
++
++static void tsin_create_win_save_phrase(int idx0, int len)
++{
++  WSP_S wsp[MAX_PHRASE_LEN];
++  int i;
++  for(i=0;i<len;i++) {
++    memcpy(wsp[i].ch, tss.chpho[i+idx0].ch, CH_SZ);
++    wsp[i].key = tss.chpho[i+idx0].pho;
++  }
++  create_win_save_phrase(wsp, len);
++}
++
++
++int feedkey_pp(KeySym xkey, int kbstate)
++{
++  char ctyp=0;
++  static u_int ii;
++  static u_short key;
++  int shift_m=kbstate&ShiftMask;
++  int ctrl_m=kbstate&ControlMask;
++  int jj,kk, idx;
++  char kno;
++  int caps_eng_tog = tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_CapsLock;
++  int status=0;
++
++
++//  dbg("feedkey_pp %x %x\n", xkey, kbstate);
++//  if (xkey=='1')
++//    dbg("aaa\n");
++
++  if (caps_eng_tog) {
++    gboolean new_tsin_pho_mode = ! gdk_keymap_get_caps_lock_state(gdk_keymap_get_default());
++    if (current_CS->tsin_pho_mode != new_tsin_pho_mode) {
++      close_selection_win();
++      tsin_set_eng_ch(new_tsin_pho_mode);
++    }
++  }
++
++   if (kbstate & (Mod1Mask|Mod4Mask|Mod5Mask)) {
++//     dbg("ret\n");
++     return 0;
++   }
++
++   // Shift has autorepeat on win32
++   if ((xkey==XK_Shift_L||xkey==XK_Shift_R) && !key_press_alt) {
++//	  dbg("feedkey_pp\n");
++     key_press_alt = TRUE;
++     key_press_ctrl = FALSE;
++   } else
++   if ((xkey==XK_Control_L||xkey==XK_Control_R) && !key_press_ctrl && tss.pre_selN) {
++//	  dbg("feedkey_pp\n");
++     key_press_ctrl = TRUE;
++     key_press_alt = FALSE;
++     return TRUE;
++   } else {
++     key_press_alt = FALSE;
++     key_press_ctrl = FALSE;
++   }
++
++   if (!tsin_pho_mode() && !tss.c_len && hime_pop_up_win && xkey!=XK_Caps_Lock) {
++     hide_win0();
++     gboolean is_ascii = (xkey>=' ' && xkey<0x7f) && !ctrl_m;
++
++     if (caps_eng_tog && is_ascii) {
++       if (hime_capslock_lower)
++         case_inverse(&xkey, shift_m);
++       send_ascii(xkey);
++       return 1;
++     }
++     else {
++       if (tss.tsin_half_full && is_ascii) {
++         send_text(half_char_to_full_char(xkey));
++         return 1;
++       }
++       else {
++         return 0;
++       }
++     }
++   }
++
++   int o_sel_pho = tss.sel_pho;
++   close_win_pho_near();
++
++   switch (xkey) {
++     case XK_Escape:
++       tsin_reset_in_pho0();
++       if (typ_pho_empty()) {
++         if (!tss.c_len)
++           return 0;
++         if (!o_sel_pho && tsin_tab_phrase_end) {
++           goto tab_phrase_end;
++         }
++       }
++       tsin_reset_in_pho();
++       return 1;
++     case XK_Return:
++     case XK_KP_Enter:
++        if (shift_m) {
++          if (!tss.c_len)
++            return 0;
++          int idx0 = tss.c_idx;
++          if (tss.c_len == tss.c_idx)
++            idx0 = 0;
++          int len = tss.c_len - idx0;
++          if (len > MAX_PHRASE_LEN)
++            return 0;
++          tsin_create_win_save_phrase(idx0, len);
++          move_cursor_end();
++          return 1;
++        } else {
++          if (tss.sel_pho) {
++            tsin_sele_by_idx(tss.pho_menu_idx);
++          } else {
++            if (tss.c_len)
++              flush_tsin_buffer();
++            else
++            if (typ_pho_empty())
++              return 0;
++          }
++          return 1;
++        }
++     case XK_Home:
++     case XK_KP_Home:
++        close_selection_win();
++        if (!tss.c_len)
++          return 0;
++        clrcursor();
++        tss.c_idx=0;
++        drawcursor();
++        return 1;
++     case XK_End:
++     case XK_KP_End:
++        close_selection_win();
++        if (!tss.c_len)
++          return 0;
++        move_cursor_end();
++        return 1;
++     case XK_Left:
++     case XK_KP_Left:
++        return cursor_left();
++     case XK_Right:
++     case XK_KP_Right:
++        return cursor_right();
++     case XK_Caps_Lock:
++        if (caps_eng_tog) {
++#if 0
++          close_selection_win();
++          tsin_toggle_eng_ch();
++#endif
++          return 1;
++        } else
++          return 0;
++     case XK_Tab:
++        close_selection_win();
++        if (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Tab) {
++          tsin_toggle_eng_ch();
++          return 1;
++        }
++
++        if (tsin_tab_phrase_end && tss.c_len > 1) {
++tab_phrase_end:
++          if (tss.c_idx==tss.c_len)
++            tss.chpho[tss.c_idx-1].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
++          else
++            tss.chpho[tss.c_idx].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
++           call_tsin_parse();
++          return 1;
++        } else {
++          if (tss.c_len) {
++            flush_tsin_buffer();
++            return 1;
++          }
++        }
++        return 0;
++     case XK_Delete:
++     case XK_KP_Delete:
++        return cursor_delete();
++     case XK_BackSpace:
++		return cursor_backspace();
++     case XK_Up:
++     case XK_KP_Up:
++       if (!tss.sel_pho) {
++         if (tsin_use_pho_near && tss.c_len && tss.c_idx == tss.c_len) {
++           int idx = tss.c_len-1;
++           phokey_t pk = tss.chpho[idx].pho;
++
++           if (pk) {
++             void create_win_pho_near(phokey_t pho);
++             create_win_pho_near(pk);
++           }
++
++           return 1;
++         }
++
++         return tss.c_len>0;
++       }
++
++       int N;
++       N = phrase_count + pho_count - tss.current_page;
++       if (N > phkbm.selkeyN)
++         N = phkbm.selkeyN;
++       if (tss.pho_menu_idx == 0)
++         tsin_page_up();
++       else {
++         tss.pho_menu_idx--;
++         if (tss.pho_menu_idx < 0)
++           tss.pho_menu_idx = N-1;
++         disp_current_sel_page();
++       }
++       return 1;
++     case XK_Prior:
++     case XK_KP_Prior:
++     case XK_KP_Subtract:
++       if (!tss.sel_pho && tss.c_len && xkey == XK_KP_Subtract) {
++         add_to_tsin_buf_str("-");
++         return TRUE;
++       } else {
++         if (tss.c_len && !tss.sel_pho)
++           return win_sym_page_up();
++         if (tsin_page_up())
++           return TRUE;
++         return win_sym_page_up();
++       }
++     case XK_space:
++       if (!tss.c_len && !poo.ityp3_pho && !poo.typ_pho[0] && !poo.typ_pho[1] && !poo.typ_pho[2]
++           && tss.tsin_half_full) {
++         send_text(" ");	 /* Full width space */
++         return 1;
++       }
++
++       if (tsin_space_opt == TSIN_SPACE_OPT_INPUT && !poo.typ_pho[0] && !poo.typ_pho[1] && !poo.typ_pho[2] && !poo.ityp3_pho && !tss.sel_pho) {
++         if (tss.c_len)
++           flush_tsin_buffer();
++
++         close_selection_win();
++         goto asc_char;
++       }
++
++       if (!tsin_pho_mode())
++           goto asc_char;
++     case XK_Down:
++     case XK_KP_Down:
++       if (xkey==XK_space && !poo.ityp3_pho && (poo.typ_pho[0]||poo.typ_pho[1]||poo.typ_pho[2])) {
++         kno=0;
++#if 1
++         ctyp=3;
++//         status = inph_typ_pho(xkey);
++#endif
++         goto llll1;
++       }
++
++change_char:
++       if (!tss.c_len)
++         return 0;
++
++       idx = tss.c_idx==tss.c_len ? tss.c_idx - 1 : tss.c_idx;
++       if (!tss.chpho[idx].pho)
++         return 1;
++
++       if (!tss.sel_pho) {
++         open_select_pho();
++       } else {
++         int N = phrase_count + pho_count - tss.current_page;
++         if (N > phkbm.selkeyN)
++           N = phkbm.selkeyN;
++         if (tss.pho_menu_idx == N-1 || xkey == XK_space)
++           tsin_page_down();
++         else {
++           tss.pho_menu_idx = (tss.pho_menu_idx+1) % N;
++           disp_current_sel_page();
++         }
++       }
++       return 1;
++     case XK_Next:
++     case XK_KP_Next:
++     case XK_KP_Add:
++       if (!tss.sel_pho && tss.c_len && xkey == XK_KP_Add) {
++         add_to_tsin_buf_str("+");
++         return TRUE;
++       } else {
++         if (tss.c_len && !tss.sel_pho)
++           return win_sym_page_down();
++		 if (tsin_page_down())
++           return TRUE;
++		 return win_sym_page_down();
++	   }
++     case '\'':  // single quote
++       if (phkbm.phokbm[xkey][0].num && !pin_juyin)
++         goto other_keys;
++       else {
++	 return pre_punctuation_hsu(xkey);
++       }
++     case 'q':
++     case 'Q':
++       if (b_hsu_kbm && tsin_pho_mode())
++         goto change_char;
++     default:
++other_keys:
++       if ((kbstate & ControlMask)) {
++         if (xkey=='u') {
++           if (tss.c_len) {
++             clear_tsin_buffer();
++             if (hime_pop_up_win)
++               hide_win0();
++             return 1;
++           } else
++             return 0;
++         } else if (tsin_buffer_editing_mode && xkey == 'e') { //ctrl+e only works when user enabled tsin_buffer_editing_mode
++           //toggler
++           tss.tsin_buffer_editing ^= 1;
++           return 1;
++         } else if (xkey>='1' && xkey<='9') {
++           if (!tss.c_len)
++             return 0;
++           if (!tss.c_idx)
++             return 1;
++
++           int len = xkey - '0';
++           int idx0 = tss.c_idx - len;
++
++           if (idx0 < 0)
++             return 1;
++
++           tsin_create_win_save_phrase(idx0, len);
++           return 1;
++         } else {
++           return 0;
++         }
++       }
++
++       char xkey_lcase = xkey;
++       if ('A' <= xkey && xkey <= 'Z') {
++         xkey_lcase = tolower(xkey);
++       }
++
++
++       if (tsin_buffer_editing_mode && xkey == '\\') {
++         tss.tsin_buffer_editing ^= 1;
++         if (tss.tsin_buffer_editing && tss.c_idx==tss.c_len)
++           cursor_left();
++         return TRUE;
++       }
++
++       if (!tss.c_len)
++         tss.tsin_buffer_editing = FALSE;
++
++       if (tss.tsin_buffer_editing && !tss.sel_pho) {
++         if (xkey_lcase=='h' || xkey_lcase=='j')
++           return cursor_left();
++         else
++         if (xkey_lcase=='l' || xkey_lcase=='k')
++           return cursor_right();
++         else
++         if (xkey_lcase=='x')
++           return cursor_delete();
++         else
++           return TRUE;
++       }
++
++       if (xkey >= XK_KP_0 && xkey<=XK_KP_9)
++         xkey_lcase = xkey - XK_KP_0 + '0';
++
++       gboolean use_pre_sel;
++       use_pre_sel = tss.pre_selN && !tss.sel_pho && xkey < 127 && !phkbm.phokbm[xkey][0].num;
++
++       char *pp;
++       if ((pp=strchr(pho_selkey,xkey_lcase)) && (tss.sel_pho || tss.ctrl_pre_sel || use_pre_sel)) {
++         int c=pp-pho_selkey;
++
++         if (tss.sel_pho) {
++           if (tsin_pho_sel(c))
++             return 1;
++         } else
++         if (tss.ctrl_pre_sel || use_pre_sel) {
++           tss.ctrl_pre_sel = FALSE;
++           if (tsin_sele_by_idx(c))
++             return TRUE;
++           else {
++             close_selection_win();
++           }
++         }
++
++         goto scan_it;
++       }
++
++       tss.sel_pho=tss.current_page=0;
++   }
++
++   KeySym key_pad;
++   key_pad = keypad_proc(xkey);
++
++   if (!xkey || (xkey > 0x7e && !key_pad))
++     return 0;
++
++   if (key_pad && !tss.c_len && !tss.tsin_half_full)
++     return 0;
++
++   if (!tsin_pho_mode() || (poo.typ_pho[0]!=BACK_QUOTE_NO && (shift_m || key_pad ||
++       (!phkbm.phokbm[xkey][0].num && !phkbm.phokbm[xkey][0].typ)))) {
++       if (tsin_pho_mode() && !shift_m && strchr(hsu_punc, xkey) && !phkbm.phokbm[xkey][0].num) {
++         if (pre_punctuation_hsu(xkey))
++           return 1;
++       }
++
++       if (key_pad)
++         xkey = key_pad;
++asc_char:
++        if (shift_m) {
++          if (pre_sel_handler(xkey)) {
++            call_tsin_parse();
++            return 1;
++          }
++
++          if (tsin_pho_mode() && pre_punctuation(xkey))
++            return 1;
++        }
++
++        if (shift_m && tsin_pho_mode())  {
++          char *ppp=strchr(ochars,xkey);
++
++          if (!(kbstate&LockMask) && ppp && !((ppp-ochars) & 1))
++            xkey=*(ppp+1);
++
++        } else {
++          if (!tsin_pho_mode() && caps_eng_tog && hime_capslock_lower) {
++            case_inverse(&xkey, shift_m);
++          }
++        }
++
++        if (xkey > 127)
++          return 0;
++        char tstr[CH_SZ + 1];
++        bzero(tstr, sizeof(tstr));
++
++        u_char tt=xkey;
++
++        if (tss.tsin_half_full) {
++          strcpy(tstr, half_char_to_full_char(xkey));
++        } else {
++          tstr[0] = tt;
++        }
++
++        if (!tss.c_len) {
++          send_text(tstr);
++          return 1;
++        }
++
++        shift_ins();
++
++        memcpy(tss.chpho[tss.c_idx].ch, tstr, CH_SZ);
++
++        set_fixed(tss.c_idx, 1);
++        phokey_t tphokeys[32];
++        tphokeys[0]=0;
++        utf8_pho_keys(tss.chpho[tss.c_idx].ch, tphokeys);
++
++        disp_char_chbuf(tss.c_idx);
++        tss.chpho[tss.c_idx].pho=tphokeys[0];
++        tss.c_idx++;
++        if (tss.c_idx < tss.c_len)
++          prbuf();
++
++        if (hime_pop_up_win)
++          show_win0();
++
++        drawcursor();
++        return 1;
++   }
++
++
++     if (xkey > 127) {
++       return 0;
++     }
++
++     // for hsu & et26
++     if (xkey >= 'A' && xkey <='Z' && poo.typ_pho[0]!=BACK_QUOTE_NO)
++       xkey+=0x20;
++//     printf("bbbb %c\n", xkey);
++
++llll1:
++     status = inph_typ_pho(xkey);
++     if (hime_pop_up_win)
++         show_win0();
++
++     if (poo.typ_pho[3] || (status&PHO_STATUS_OK_NEW))
++       ctyp = 3;
++
++//     dbg("status %d %d\n", status, ctyp);
++     jj=0;
++     kk=1;
++llll2:
++     if (ctyp==3) {
++       poo.ityp3_pho=1;  /* last key is entered */
++
++       if (!tsin_tone_char_input && !poo.typ_pho[0] && !poo.typ_pho[1] && !poo.typ_pho[2]) {
++         clrin_pho_tsin();
++         dbg("no pho input\n");
++         return TRUE;
++       }
++     }
++
++     disp_in_area_pho_tsin();
++
++     key = pho2key(poo.typ_pho);
++
++     pho_play(key);
++
++     int vv=hash_pho[(int)poo.typ_pho[0]];
++
++     phokey_t ttt=0xffff;
++     while (vv<idxnum_pho) {
++       ttt=idx_pho[vv].key;
++       if (poo.typ_pho[0]!=BACK_QUOTE_NO) {
++         if (!poo.typ_pho[0]) ttt &= ~(31<<9);
++         if (!poo.typ_pho[1]) ttt &= ~(3<<7);
++         if (!poo.typ_pho[2]) ttt &= ~(15<<3);
++         if (!poo.typ_pho[3]) ttt &= ~(7);
++       }
++       if (ttt>=key) break;
++       else
++       vv++;
++     }
++#if 0
++     printf("aaaa vv:%d  idxnum_pho:%d   ttt:%x key:%x\n",vv, idxnum_pho, ttt, key);
++#endif
++     if (!pin_juyin && (ttt > key || (poo.ityp3_pho && idx_pho[vv].key!=key))) {
++       while (jj<4) {
++         while(kk<3)
++         if (phkbm.phokbm[(int)poo.inph[jj]][kk].num ) {
++           if (kk) {
++             ctyp=phkbm.phokbm[(int)poo.inph[jj]][kk-1].typ;
++             poo.typ_pho[(int)ctyp]=0;
++           }
++           kno=phkbm.phokbm[(int)poo.inph[jj]][kk].num;
++           ctyp=phkbm.phokbm[(int)poo.inph[jj]][kk].typ;
++           poo.typ_pho[(int)ctyp]=kno;
++           kk++;
++           goto llll2;
++         } else kk++;
++         jj++;
++         kk=1;
++       }
++
++       bell(); poo.ityp3_pho=poo.typ_pho[3]=0;
++       disp_in_area_pho_tsin();
++//       dbg("not found ...\n");
++       return 1;
++     }
++
++     if (poo.typ_pho[0]==L_BRACKET_NO||poo.typ_pho[0]==R_BRACKET_NO || (poo.typ_pho[0]==BACK_QUOTE_NO && poo.typ_pho[1]))
++       poo.ityp3_pho = 1;
++
++     if (key==0 || !poo.ityp3_pho) {
++       if (key)
++         tsin_scan_pre_select(TRUE);
++//       dbg("ret a\n");
++       return 1;
++     }
++
++     ii=idx_pho[vv].start;
++     poo.start_idx=ii;
++     poo.stop_idx = idx_pho[vv+1].start;
++#if 0
++     printf("%x %x %d vv:%d idxnum_pho:%d-->", ttt, key, poo.start_idx, vv, idxnum_pho);
++     utf8_putchar(pho_idx_str(poo.start_idx));
++     puts("<---");
++#endif
++
++   if (!tss.c_len && poo.typ_pho[0]==BACK_QUOTE_NO && poo.stop_idx - poo.start_idx == 1)
++     send_text(pho_idx_str(poo.start_idx));  // it's ok since ,. are 3 byte, last one \0
++   else
++     put_u8_char(poo.start_idx, key, (status&PHO_STATUS_TONE)>0);
++
++   call_tsin_parse();
++
++   disp_ph_sta();
++   if (status & PHO_STATUS_PINYIN_LEFT) {
++     poo.ityp3_pho=0;
++     disp_in_area_pho_tsin();
++   } else {
++     clrin_pho_tsin();
++     clr_in_area_pho_tsin();
++   }
++   drawcursor();
++   hide_pre_sel();
++
++scan_it:
++   tsin_scan_pre_select(FALSE);
++
++   return 1;
++}
++
++
++int feedkey_pp_release(KeySym xkey, int kbstate)
++{
++  switch (xkey) {
++     case XK_Shift_L:
++     case XK_Shift_R:
++// dbg("release xkey %x\n", xkey);
++        if (((tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Shift) ||
++             (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftL && xkey == XK_Shift_L) ||
++             (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftR && xkey == XK_Shift_R)) &&
++	    key_press_alt) {
++          if (!test_mode) {
++            close_selection_win();
++            tsin_toggle_eng_ch();
++          }
++	  key_press_alt = FALSE;
++          return 1;
++	} else
++          return 0;
++     case XK_Control_L:
++     case XK_Control_R:
++        if (key_press_ctrl && tss.pre_selN) {
++          if (!test_mode)
++	    tss.ctrl_pre_sel = TRUE;
++	  key_press_ctrl = FALSE;
++          return 1;
++	} else
++          return 0;
++     default:
++        return 0;
++  }
++}
++
++
++void tsin_remove_last()
++{
++  if (!tss.c_len)
++    return;
++  tss.c_len--;
++  tss.c_idx--;
++}
++
++
++gboolean save_phrase_to_db2(CHPHO *chph, int len)
++{
++   phokey_t pho[MAX_PHRASE_LEN];
++   char ch[MAX_PHRASE_LEN * CH_SZ * 2];
++
++   chpho_extract_cha(chph, len, pho, ch);
++
++   return save_phrase_to_db(pho, ch, len, 1);
++}
++
++#include "im-client/hime-im-client-attr.h"
++
++
++int tsin_get_preedit(char *str, HIME_PREEDIT_ATTR attr[], int *cursor, int *comp_flag)
++{
++  int i;
++  int tn=0;
++  int attrN=0;
++#if DEBUG && 0
++  dbg("tsin_get_preedit\n");
++#endif
++
++  gboolean ap_only = hime_edit_display_ap_only();
++
++  for(i=0; i<tss.c_len; i++) {
++    if (tn>=HIME_PREEDIT_MAX_STR-4*CH_SZ-1)
++      goto fin;
++    if (i==tss.c_idx && hime_display_on_the_spot_key()) {
++      tn += get_in_area_pho_tsin_str(str+tn);
++    }
++
++    strcpy(str+tn, tss.chpho[i].ch);
++    tn+=strlen(tss.chpho[i].ch);
++  }
++
++fin:
++  str[tn]=0;
++
++  if (i==tss.c_idx && hime_display_on_the_spot_key())
++    get_in_area_pho_tsin_str(str+tn);
++
++#if DEBUG && 0
++  dbg("'%s'\n", str);
++#endif
++  if (tss.c_len) {
++    attr[0].flag=HIME_PREEDIT_ATTR_FLAG_UNDERLINE;
++    attr[0].ofs0=0;
++    attr[0].ofs1=tss.c_len;
++    attrN++;
++
++
++    // for firefox 4
++    if (ap_only && tss.c_idx < tss.c_len) {
++      attr[1].ofs0=tss.c_idx;
++      attr[1].ofs1=tss.c_idx+1;
++      attr[1].flag=HIME_PREEDIT_ATTR_FLAG_REVERSE;
++      attrN++;
++    }
++  }
++
++  *cursor = tss.c_idx;
++  *comp_flag = !typ_pho_empty();
++  if (gwin1 && GTK_WIDGET_VISIBLE(gwin1))
++    *comp_flag|=2;
++#if 1
++  if (tss.c_len && !ap_only)
++	*comp_flag|=4;
++#endif
++
++  return attrN;
++}
++
++int tsin_reset()
++{
++//  dbg("tsin_reset\n");
++  if (!gwin0)
++    return 0;
++  int v = tss.c_len > 0;
++  tsin_reset_in_pho0();
++  clear_tsin_buffer();
++
++  return v;
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/tsin.h b/src/plugins/platforminputcontexts/hime/include/tsin.h
+new file mode 100644
+index 0000000..0055e42
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/tsin.h
+@@ -0,0 +1,68 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++extern int phcount;
++extern int hashidx[];
++//extern int *phidx;
++//extern FILE *fph;
++
++typedef struct CHPHO {
++  char *ch;
++  char cha[CH_SZ+1];
++  phokey_t pho;
++  u_short flag;
++  char psta; // phrase start index
++} CHPHO;
++
++enum {
++  FLAG_CHPHO_FIXED=1,    // user selected the char, so it should not be changed
++  FLAG_CHPHO_PHRASE_HEAD=2,
++  FLAG_CHPHO_PHRASE_USER_HEAD=4,
++  FLAG_CHPHO_PHRASE_VOID=8,
++  FLAG_CHPHO_PHRASE_BODY=16,
++  FLAG_CHPHO_PHO_PHRASE=32,
++  FLAG_CHPHO_PINYIN_TONE=64,
++  FLAG_CHPHO_GTAB_BUF_EN_NO_SPC=128,
++  FLAG_CHPHO_PHRASE_TAIL=0x100,
++};
++
++void extract_pho(int chpho_idx, int plen, phokey_t *pho);
++gboolean tsin_seek(void *pho, int plen, int *r_sti, int *r_edi, char *tone_off);
++void load_tsin_entry(int idx, char *len, usecount_t *usecount, void *pho, u_char *ch);
++gboolean check_fixed_mismatch(int chpho_idx, char *mtch, int plen);
++gboolean tsin_pho_mode();
++char *get_chpho_pinyin_set(char *set_arr);
++
++#define TSIN_GTAB_KEY "!!!!gtab-keys"
++
++typedef struct {
++  char signature[32];
++  int version, flag;
++  int keybits, maxkey;
++  char keymap[128];
++} TSIN_GTAB_HEAD;
++
++typedef struct PRE_SEL {
++  u_int64_t phkey[MAX_PHRASE_LEN];  // gtab 4-byte is actually stored as u_int not u_int64_t
++//  int phidx;
++  char str[MAX_PHRASE_LEN*CH_SZ+1];
++  int len;
++  usecount_t usecount;
++} PRE_SEL;
++
++extern gboolean tsin_is_gtab;
++extern int ph_key_sz;
+diff --git a/src/plugins/platforminputcontexts/hime/include/util.c b/src/plugins/platforminputcontexts/hime/include/util.c
+new file mode 100644
+index 0000000..0d81b1b
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/util.c
+@@ -0,0 +1,150 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include <errno.h>
++
++#if !CLIENT_LIB && DEBUG
++static FILE *out_fp;
++#endif
++
++void p_err(char *fmt,...)
++{
++  va_list args;
++  char out[4096];
++
++  va_start(args, fmt);
++  vsprintf(out, fmt, args);
++  va_end(args);
++
++  fprintf(stderr, "%s\n", out);
++
++#if DEBUG && 1
++  abort();
++#else
++  if (getenv("HIME_ERR_COREDUMP"))
++    abort();
++  exit(-1);
++#endif
++}
++
++#if !CLIENT_LIB && DEBUG
++static void init_out_fp()
++{
++  if (!out_fp) {
++    if (getenv("HIME_DBG_TMP") || 0) {
++      char fname[64];
++      sprintf(fname, "%s/himedbg-%d-%d", g_get_tmp_dir(), getuid(), getpid());
++      out_fp = fopen(fname, "w");
++    }
++
++    if (!out_fp)
++      out_fp = stdout;
++  }
++}
++#endif
++
++#if !CLIENT_LIB
++void dbg_time(char *fmt,...)
++{
++#if DEBUG
++  va_list args;
++  time_t t;
++
++  init_out_fp();
++
++  time(&t);
++  struct tm *ltime = localtime(&t);
++  dbg("%02d:%02d:%02d ", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
++
++  va_start(args, fmt);
++  vfprintf(out_fp, fmt, args);
++  fflush(out_fp);
++  va_end(args);
++#endif
++}
++#endif
++
++#if DEBUG
++void __hime_dbg_(char *fmt,...)
++{
++  va_list args;
++
++  init_out_fp();
++
++  va_start(args, fmt);
++  vfprintf(out_fp, fmt, args);
++  fflush(out_fp);
++  va_end(args);
++}
++#endif
++
++char *sys_err_strA()
++{
++  return (char *)strerror(errno);
++}
++
++void *zmalloc(int n)
++{
++  void *p =  malloc(n);
++  bzero(p, n);
++  return p;
++}
++#if !HIME_IME
++
++void *memdup(void *p, int n)
++{
++  if (!p || !n)
++    return NULL;
++  void *q;
++  q = malloc(n);
++  memcpy(q, p, n);
++  return q;
++}
++
++// can handle eol with \n \r \n\r \r\n
++char *myfgets(char *buf, int bufN, FILE *fp)
++{
++	char *out = buf;
++//	int rN = 0;
++	while (!feof(fp) && out - buf < bufN) {
++		char a, b;
++		a = 0;
++		if (fread(&a, 1, 1, fp) != 1)
++			break;
++		if (a =='\n') {
++			b = 0;
++			if (fread(&b, 1, 1, fp)==1)
++				if (b!='\r')
++					fseek(fp, -1, SEEK_CUR);
++			break;
++		} else
++		if (a =='\r') {
++			b = 0;
++			if (fread(&b, 1, 1, fp)==1)
++				if (b!='\n')
++					fseek(fp, -1, SEEK_CUR);
++			break;
++		}
++
++		*(out++) = a;
++	}
++
++	*out = 0;
++	return buf;
++}
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/util.h b/src/plugins/platforminputcontexts/hime/include/util.h
+new file mode 100644
+index 0000000..62fbfc9
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/util.h
+@@ -0,0 +1,12 @@
++void p_err(char *fmt,...);
++
++#ifndef DEBUG
++#define DEBUG 0
++#endif
++
++#if DEBUG
++void __hime_dbg_(char *fmt,...);
++#define dbg(fmt,...) __hime_dbg_("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__)
++#else
++#define dbg(...) do {} while (0)
++#endif
+diff --git a/src/plugins/platforminputcontexts/hime/include/win-save-phrase.c b/src/plugins/platforminputcontexts/hime/include/win-save-phrase.c
+new file mode 100644
+index 0000000..3e54b17
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/win-save-phrase.c
+@@ -0,0 +1,226 @@
++/* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "pho.h"
++#include "win-save-phrase.h"
++#include "gtab.h"
++
++extern int c_len;
++extern gboolean test_mode;
++
++
++typedef struct {
++  WSP_S *mywsp;
++  int mywspN;
++  GtkWidget *label_countdown, *win;
++  int countdown, countdown_handle;
++} SAVE_SESS;
++
++static void wsp_str(WSP_S *wsp, int wspN, char *out)
++{
++  int i;
++  int ofs=0;
++
++  for(i=0;i<wspN;i++) {
++//    utf8_putchar(wsp[i].ch);
++	int n = utf8cpy(out+ofs, wsp[i].ch);
++	ofs+=n;
++  }
++
++//  out[ofs]=0;
++//  dbg(" c_len:%d wsp %s\n", c_len, out);
++}
++
++
++static void free_mywsp(SAVE_SESS *sess)
++{
++  free(sess->mywsp); sess->mywsp=NULL;
++  free(sess);
++}
++
++
++static gboolean close_win_save_phrase(GtkWidget *widget, gpointer data)
++{
++  SAVE_SESS *sess = (SAVE_SESS *)data;
++
++  g_source_remove(sess->countdown_handle);
++  gtk_widget_destroy(sess->win);
++  free_mywsp(sess);
++  return TRUE;
++}
++
++#if 0
++static gint delete_event( GtkWidget *widget,
++                   GdkEvent  *event,
++                   gpointer   data)
++{
++  free_mywsp(data);
++  return FALSE;
++}
++#endif
++
++extern int ph_key_sz;
++
++static gboolean cb_ok(GtkWidget *widget, gpointer data)
++{
++  SAVE_SESS *sess = (SAVE_SESS *)data;
++  g_source_remove(sess->countdown_handle);
++
++  int i;
++  phokey_t pho[MAX_PHRASE_LEN];
++  u_int pho32[MAX_PHRASE_LEN];
++  u_int64_t pho64[MAX_PHRASE_LEN];
++  char tt[512];
++  void *dat = NULL;
++  wsp_str(sess->mywsp, sess->mywspN, tt);
++
++  if (ph_key_sz==2) {
++    for(i=0;i<sess->mywspN;i++)
++      pho[i] = sess->mywsp[i].key;
++    dat = pho;
++  }
++  else
++  if (ph_key_sz==4) {
++    for(i=0;i< sess->mywspN;i++) {
++      pho32[i] = sess->mywsp[i].key;
++    }
++    dat = pho32;
++  }
++  else
++  if (ph_key_sz==8) {
++    for(i=0;i< sess->mywspN;i++)
++      pho64[i] = sess->mywsp[i].key;
++    dat = pho64;
++  }
++
++  save_phrase_to_db(dat, tt, sess->mywspN, 1);
++
++  gtk_widget_destroy(sess->win);
++
++  free_mywsp(sess);
++  return TRUE;
++}
++
++static void disp_countdown(SAVE_SESS *sess)
++{
++  char tt[64];
++
++  sprintf(tt, _("%d 秒後自動加入"), sess->countdown);
++  gtk_label_set_text(GTK_LABEL(sess->label_countdown), tt);
++}
++
++
++gboolean timeout_countdown(gpointer data)
++{
++  SAVE_SESS *sess = (SAVE_SESS *)data;
++
++  if (!sess->countdown) {
++    cb_ok(NULL, data);
++    return FALSE;
++  }
++
++  sess->countdown--;
++  disp_countdown(sess);
++  return TRUE;
++}
++
++
++void create_win_save_phrase(WSP_S *wsp, int wspN)
++{
++  if (!wspN)
++    return;
++
++  SAVE_SESS *sess = tzmalloc(SAVE_SESS, 1);
++
++  GtkWidget *main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++  gtk_window_set_has_resize_grip(GTK_WINDOW(main_window), FALSE);
++  sess->win = main_window;
++
++  gtk_window_set_default_size(GTK_WINDOW (main_window), 20, 10);
++
++  gtk_window_set_title(GTK_WINDOW(main_window), _("加片語到詞庫"));
++
++#if 0
++  g_signal_connect (G_OBJECT (main_window), "delete_event",
++                     G_CALLBACK (delete_event), sess);
++#endif
++
++  GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
++  gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox), GTK_ORIENTATION_VERTICAL);
++  gtk_container_add (GTK_CONTAINER (main_window), vbox);
++
++  char tt[512];
++  tt[0] = 0;
++  wsp_str(wsp, wspN, tt);
++
++  gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new(tt), FALSE, FALSE, 0);
++
++  int i;
++  for(i=0; i<wspN; i++) {
++    if (ph_key_sz==2)
++      strcat(tt, phokey_to_str(wsp[i].key));
++    strcat(tt, " ");
++  }
++
++  if (tt[0])
++    gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new(tt), FALSE, FALSE, 0);
++
++  sess->mywsp = tmemdup(wsp, WSP_S, wspN);
++  sess->mywspN = wspN;
++
++  GtkWidget *hbox_cancel_ok = gtk_hbox_new (FALSE, 10);
++  gtk_box_pack_start (GTK_BOX (vbox), hbox_cancel_ok , FALSE, FALSE, 5);
++
++  GtkWidget *button_ok = gtk_button_new_from_stock (GTK_STOCK_OK);
++  gtk_box_pack_start (GTK_BOX (hbox_cancel_ok), button_ok, TRUE, TRUE, 5);
++
++  GtkWidget *button_cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
++  gtk_box_pack_start (GTK_BOX (hbox_cancel_ok), button_cancel, TRUE, TRUE, 0);
++
++  sess->label_countdown = gtk_label_new(NULL);
++  gtk_box_pack_start (GTK_BOX (vbox), sess->label_countdown, FALSE, FALSE, 5);
++
++  gtk_widget_realize(main_window);
++  set_no_focus(main_window);
++
++//  dbg("mmmmmmmmmmmmm\n");
++
++  GTK_WIDGET_SET_FLAGS (button_ok, GTK_CAN_DEFAULT);
++  gtk_widget_grab_default (button_ok);
++
++
++#if 1
++//  dbg("main_window %x\n", main_window);
++  g_signal_connect (G_OBJECT (button_cancel), "clicked",
++                            G_CALLBACK (close_win_save_phrase),
++                            sess);
++
++  g_signal_connect (G_OBJECT (button_ok), "clicked",
++                            G_CALLBACK (cb_ok),
++                            sess);
++#endif
++
++  gtk_window_present(GTK_WINDOW(main_window));
++  gtk_window_set_keep_above(GTK_WINDOW(main_window), TRUE);
++//  gtk_window_set_modal(GTK_WINDOW(main_window), TRUE);
++
++  sess->countdown = 3;
++  disp_countdown(sess);
++  sess->countdown_handle = g_timeout_add(1000, timeout_countdown, sess);
++  gtk_widget_show_all(main_window);
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/win-save-phrase.h b/src/plugins/platforminputcontexts/hime/include/win-save-phrase.h
+new file mode 100644
+index 0000000..4af2578
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/win-save-phrase.h
+@@ -0,0 +1,7 @@
++typedef struct {
++	u_int64_t key;
++	char ch[CH_SZ];
++	GtkWidget *opt;
++} WSP_S;
++
++void create_win_save_phrase(WSP_S *wsp, int wspN);
+diff --git a/src/plugins/platforminputcontexts/hime/include/win1.c b/src/plugins/platforminputcontexts/hime/include/win1.c
+new file mode 100644
+index 0000000..5f9959a
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/win1.c
+@@ -0,0 +1,432 @@
++/* Copyright (C) 2004-2012 Edward Der-Hua Liu, Hsin-Chu, Taiwan
++ *
++ * 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 version 2.1
++ * of the License.
++ *
++ * 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 library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "hime.h"
++#include "pho.h"
++#include "gst.h"
++#include "win1.h"
++
++GtkWidget *gwin1;
++static GtkWidget *frame;
++static char wselkey[16];
++static int wselkeyN;
++//Window xwin1;
++
++#define SELEN (15)
++
++static GtkWidget *labels_sele[SELEN], *labels_seleR[SELEN];
++static GtkWidget *eve_sele[SELEN], *eve_seleR[SELEN];
++static GtkWidget *arrow_up, *arrow_down;
++
++void hide_selections_win();
++static cb_page_ud_t cb_page_up, cb_page_down;
++static int c_config;
++
++static int current_config()
++{
++  return (tsin_tail_select_key<<9) | (pho_candicate_col_N<<5) | wselkeyN << 1|
++    pho_candicate_R2L;
++}
++
++static int idx_to_x(int tN, int i)
++{
++    if (tN > pho_candicate_col_N)
++      tN = pho_candicate_col_N;
++
++    int x = i % tN;
++    if (pho_candicate_R2L)
++      x = tN - 1 - x;
++    return x;
++}
++
++static gboolean button_scroll_event_tsin(GtkWidget *widget,GdkEventScroll *event, gpointer user_data)
++{
++  switch (event->direction) {
++    case GDK_SCROLL_UP:
++      if (cb_page_up)
++        cb_page_up();
++      break;
++    case GDK_SCROLL_DOWN:
++      if (cb_page_down)
++        cb_page_down();
++      break;
++    default:
++      break;
++  }
++
++  return TRUE;
++}
++
++
++
++void create_win1()
++{
++  if (gwin1)
++    return;
++
++  gwin1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++  gtk_window_set_has_resize_grip(GTK_WINDOW(gwin1), FALSE);
++  gtk_widget_realize (gwin1);
++
++  set_no_focus(gwin1);
++
++  g_signal_connect (G_OBJECT (gwin1), "scroll-event", G_CALLBACK (button_scroll_event_tsin), NULL);
++}
++
++
++void change_win1_font(), force_preedit_shift();
++
++
++static cb_selec_by_idx_t cb_sele_by_idx;
++
++static void mouse_button_callback( GtkWidget *widget,GdkEventButton *event, gpointer data)
++{
++  int v;
++  switch (event->button) {
++    case 1:
++      v = GPOINTER_TO_INT(data);
++      if (cb_sele_by_idx)
++        cb_sele_by_idx(v);
++      force_preedit_shift();
++      break;
++  }
++}
++
++
++static void cb_arrow_up (GtkWidget *button, gpointer user_data)
++{
++  if (cb_page_up)
++    cb_page_up();
++}
++static void cb_arrow_down (GtkWidget *button, gpointer user_data)
++{
++  if (cb_page_down)
++   cb_page_down();
++}
++
++void set_win1_cb(cb_selec_by_idx_t sele_by_idx, cb_page_ud_t page_up, cb_page_ud_t page_down)
++{
++  cb_sele_by_idx = sele_by_idx;
++  cb_page_up = page_up;
++  cb_page_down = page_down;
++}
++
++void create_win1_gui()
++{
++  if (frame)
++    return;
++//  dbg("create_win1_gui %s\n", wselkey);
++
++  frame = gtk_frame_new(NULL);
++  gtk_container_add (GTK_CONTAINER(gwin1), frame);
++
++  GtkWidget *vbox_top = gtk_vbox_new (FALSE, 0);
++  gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox_top), GTK_ORIENTATION_VERTICAL);
++  gtk_container_add (GTK_CONTAINER(frame), vbox_top);
++
++  GtkWidget *eve_box_up = gtk_event_box_new();
++  gtk_event_box_set_visible_window (GTK_EVENT_BOX(eve_box_up), FALSE);
++  gtk_box_pack_start (GTK_BOX (vbox_top), eve_box_up, FALSE, FALSE, 0);
++  arrow_up = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_IN);
++  gtk_container_add(GTK_CONTAINER(eve_box_up), arrow_up);
++  g_signal_connect (G_OBJECT (eve_box_up), "button-press-event",
++                      G_CALLBACK (cb_arrow_up), NULL);
++
++  int c_rowN = (wselkeyN + pho_candicate_col_N - 1) / pho_candicate_col_N * pho_candicate_col_N;
++  int tablecolN = pho_candicate_col_N;
++
++  if (!tsin_tail_select_key)
++    tablecolN *= 2;
++
++  c_config = current_config();
++
++  GtkWidget *table = gtk_table_new(c_rowN, tablecolN, FALSE);
++  gtk_box_pack_start (GTK_BOX (vbox_top), table, FALSE, FALSE, 0);
++
++  int i;
++  for(i=0; i < wselkeyN; i++)
++  {
++    int y = i/pho_candicate_col_N;
++    int x = idx_to_x(SELEN+1, i);
++
++    if (!tsin_tail_select_key)
++      x*=2;
++
++    GtkWidget *align = gtk_alignment_new(0,0,0,0);
++    gtk_table_attach_defaults(GTK_TABLE(table),align, x,x+1,y,y+1);
++    GtkWidget *event_box_pho = gtk_event_box_new();
++    gtk_event_box_set_visible_window (GTK_EVENT_BOX(event_box_pho), FALSE);
++    GtkWidget *label = gtk_label_new(NULL);
++    gtk_container_add (GTK_CONTAINER (event_box_pho), label);
++    labels_sele[i] = label;
++    eve_sele[i] = event_box_pho;
++    gtk_container_add (GTK_CONTAINER (align), event_box_pho);
++    gtk_label_set_justify(GTK_LABEL(labels_sele[i]),GTK_JUSTIFY_LEFT);
++    set_label_font_size(labels_sele[i], hime_font_size_tsin_presel);
++    g_signal_connect(G_OBJECT(event_box_pho),"button-press-event",
++                   G_CALLBACK(mouse_button_callback), GINT_TO_POINTER(i));
++
++    if (!tsin_tail_select_key) {
++      GtkWidget *alignR = gtk_alignment_new(0,0,0,0);
++      gtk_table_attach_defaults(GTK_TABLE(table), alignR, x+1,x+2,y,y+1);
++      GtkWidget *event_box_phoR = gtk_event_box_new();
++      gtk_event_box_set_visible_window (GTK_EVENT_BOX(event_box_phoR), FALSE);
++      GtkWidget *labelR = gtk_label_new(NULL);
++      gtk_container_add (GTK_CONTAINER (event_box_phoR), labelR);
++      labels_seleR[i] = labelR;
++      eve_seleR[i] = event_box_phoR;
++      gtk_container_add (GTK_CONTAINER (alignR), event_box_phoR);
++      gtk_label_set_justify(GTK_LABEL(labels_sele[i]),GTK_JUSTIFY_LEFT);
++      set_label_font_size(labels_seleR[i], hime_font_size_tsin_presel);
++      g_signal_connect(G_OBJECT(event_box_phoR),"button-press-event",
++                     G_CALLBACK(mouse_button_callback), GINT_TO_POINTER(i));
++    }
++  }
++
++  GtkWidget *eve_box_down = gtk_event_box_new();
++  gtk_event_box_set_visible_window (GTK_EVENT_BOX(eve_box_down), FALSE);
++  gtk_box_pack_start (GTK_BOX (vbox_top), eve_box_down, FALSE, FALSE, 0);
++  arrow_down = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
++  gtk_container_add(GTK_CONTAINER(eve_box_down), arrow_down);
++  g_signal_connect (G_OBJECT (eve_box_down), "button-press-event",
++                      G_CALLBACK (cb_arrow_down), NULL);
++
++  gtk_widget_show_all(gwin1);
++//  gdk_flush();
++  gtk_widget_hide(gwin1);
++
++  change_win1_font();
++}
++
++void init_tsin_selection_win()
++{
++  create_win1();
++  create_win1_gui();
++}
++
++void clear_sele()
++{
++  int i;
++
++  if (!gwin1)
++    return;
++
++  for(i=0; i < wselkeyN; i++) {
++    gtk_widget_hide(labels_sele[i]);
++    if (labels_seleR[i])
++      gtk_widget_hide(labels_seleR[i]);
++  }
++
++  gtk_widget_hide(arrow_up);
++  gtk_widget_hide(arrow_down);
++  hide_selections_win();
++}
++
++char *htmlspecialchars(char *s, char out[]);
++
++void set_sele_text(int tN, int i, char *text, int len)
++{
++  if (len < 0)
++    len=strlen(text);
++
++  char tt[128];
++  char utf8[128];
++
++  memcpy(utf8, text, len);
++  utf8[len]=0;
++  char uu[32], selma[128];
++
++  char cc[2];
++  cc[0]=wselkey[i];
++  cc[1]=0;
++  char ul[128];
++  ul[0]=0;
++
++#if 0
++  if (tss.sel_pho && i==tss.pho_menu_idx)
++    strcpy(ul, " foreground=\"yellow\" background=\"black\"");
++  else
++    sprintf(ul, "foreground=\"%s\"", hime_sel_key_color);
++#endif
++  if (tss.sel_pho && i==tss.pho_menu_idx) {
++    if (hime_win_color_use)
++      sprintf(ul, "foreground=\"white\" background=\"%s\"", tsin_cursor_color);
++    else
++      strcpy(ul, "foreground=\"white\" background=\""TSIN_CURSOR_COLOR_DEFAULT"\"");
++  } else {
++    if (hime_win_color_use)
++      sprintf(ul, "foreground=\"%s\"", hime_sel_key_color);
++    else
++      strcpy(ul, "foreground=\""HIME_SEL_KEY_COLOR_DEFAULT"\"");
++  }
++
++  sprintf(selma, "<span %s>%s</span>", ul, htmlspecialchars(cc, uu));
++
++  int x = idx_to_x(tN, i);
++  char *sep= x?" ":"";
++
++  if (tsin_tail_select_key) {
++    char vv[128];
++    snprintf(tt, sizeof(tt), "%s%s%s", sep, htmlspecialchars(utf8, vv), selma);
++  } else {
++    gtk_label_set_text(GTK_LABEL(labels_seleR[i]), utf8);
++    gtk_widget_show(labels_seleR[i]);
++    snprintf(tt, sizeof(tt), "%s%s",sep, selma);
++  }
++
++  gtk_widget_show(labels_sele[i]);
++//  dbg("tt %s\n", tt);
++  gtk_label_set_markup(GTK_LABEL(labels_sele[i]), tt);
++}
++
++void raise_tsin_selection_win()
++{
++  if (gwin1 && GTK_WIDGET_VISIBLE(gwin1))
++    gtk_window_present(GTK_WINDOW(gwin1));
++}
++
++
++void getRootXY(Window win, int wx, int wy, int *tx, int *ty);
++void disp_selections(int x, int y)
++{
++  if (!gwin1)
++    p_err("disp_selections !gwin1");
++
++  if (y < 0) {
++	 int tx;
++	 if (hime_edit_display_ap_only())
++		getRootXY(current_CS->client_win, current_CS->spot_location.x, current_CS->spot_location.y, &tx, &y);
++	 else
++		 y = win_y + win_yl;
++  }
++
++
++  int win1_xl, win1_yl;
++  get_win_size(gwin1, &win1_xl, &win1_yl);
++
++  if (x < 0) {
++    x = win_x + win_xl - win1_xl;
++    if (x < win_x)
++      x = win_x;
++  }
++
++  if (x + win1_xl > dpy_xl)
++    x = dpy_xl - win1_xl;
++
++  if (y + win1_yl > dpy_yl)
++    y = win_y - win1_yl;
++
++  gtk_window_move(GTK_WINDOW(gwin1), x, y);
++
++  if (!GTK_WIDGET_VISIBLE(gwin1)) {
++    gtk_widget_show(gwin1);
++  }
++}
++
++void hide_selections_win()
++{
++  if (!gwin1)
++    return;
++  gtk_widget_hide(gwin1);
++}
++
++void disp_arrow_up()
++{
++  gtk_widget_show(arrow_up);
++}
++
++void disp_arrow_down()
++{
++  gtk_widget_show(arrow_down);
++}
++
++#if USE_TSIN
++void destroy_win1()
++{
++  if (!gwin1)
++    return;
++  gtk_widget_destroy(gwin1);
++  frame=NULL;
++  gwin1 = NULL;
++}
++#endif
++
++void change_win1_font()
++{
++  int i;
++  if (!frame)
++    return;
++
++  GdkColor fg;
++  gdk_color_parse(hime_win_color_fg, &fg);
++#if GTK_CHECK_VERSION(2,91,6)
++  GdkRGBA rgbfg;
++  gdk_rgba_parse(&rgbfg, gdk_color_to_string(&fg));
++#endif
++
++  for(i=0; i < wselkeyN; i++) {
++    set_label_font_size(labels_sele[i], hime_font_size_tsin_presel);
++    set_label_font_size(labels_seleR[i], hime_font_size_tsin_presel);
++#if !GTK_CHECK_VERSION(2,91,6)
++    if (labels_sele[i])
++      gtk_widget_modify_fg(labels_sele[i], GTK_STATE_NORMAL, hime_win_color_use?&fg:NULL);
++    if (labels_seleR[i])
++      gtk_widget_modify_fg(labels_seleR[i], GTK_STATE_NORMAL, hime_win_color_use?&fg:NULL);
++#else
++    if (labels_sele[i])
++      gtk_widget_override_color(labels_sele[i], GTK_STATE_FLAG_NORMAL, hime_win_color_use?&rgbfg:NULL);
++    if (labels_seleR[i])
++      gtk_widget_override_color(labels_seleR[i], GTK_STATE_FLAG_NORMAL, hime_win_color_use?&rgbfg:NULL);
++#endif
++    change_win_bg(eve_sele[i]);
++    if (eve_seleR[i])
++      change_win_bg(eve_seleR[i]);
++  }
++
++  change_win_bg(gwin1);
++}
++
++void recreate_win1_if_nessary()
++{
++//  dbg("%x %x\n", current_config(), c_config);
++
++  if (!gwin1)
++    return;
++
++  if (current_config() != c_config) {
++    c_config = current_config();
++//    dbg("destroy frame\n");
++    bzero(labels_sele, sizeof(labels_sele));
++    bzero(labels_seleR, sizeof(labels_seleR));
++    bzero(eve_sele, sizeof(eve_sele));
++    bzero(eve_seleR, sizeof(eve_seleR));
++    gtk_widget_destroy(frame); frame = NULL;
++    create_win1_gui();
++  }
++}
++
++
++void set_wselkey(char *s)
++{
++  if (strcmp (wselkey, s))
++  {
++    memset (wselkey, 0x00, 16);
++    memcpy (wselkey, s, strlen (s));
++    wselkeyN = strlen (s);
++    recreate_win1_if_nessary ();
++  }
++}
+diff --git a/src/plugins/platforminputcontexts/hime/include/win1.h b/src/plugins/platforminputcontexts/hime/include/win1.h
+new file mode 100644
+index 0000000..1907861
+--- /dev/null
++++ b/src/plugins/platforminputcontexts/hime/include/win1.h
+@@ -0,0 +1,3 @@
++typedef void (*cb_selec_by_idx_t)(int);
++typedef void (*cb_page_ud_t)();
++void set_win1_cb(cb_selec_by_idx_t selc_by_idx, cb_page_ud_t cb_page_up, cb_page_ud_t cb_page_down);
 diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
-index faea54b..e31be7c 100644
+index faea54b..0f96509 100644
 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
 +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
 @@ -1,7 +1,8 @@
@@ -11261,8 +33669,8 @@ index faea54b..e31be7c 100644
  
  qtHaveModule(dbus) {
 -!mac:!win32:SUBDIRS += ibus
-+# Patch: Adding fcitx input context plugin to our static build.
-+!mac:!win32:SUBDIRS += ibus fcitx
++# Patch: Adding fcitx/hime input context plugin to our static build.
++!mac:!win32:SUBDIRS += ibus fcitx hime
  }
  
  contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose
diff --git a/Telegram/SourceFiles/qt_static_plugins.cpp b/Telegram/SourceFiles/qt_static_plugins.cpp
index 1d4896a63..b975c7a84 100644
--- a/Telegram/SourceFiles/qt_static_plugins.cpp
+++ b/Telegram/SourceFiles/qt_static_plugins.cpp
@@ -36,4 +36,5 @@ Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin)
 Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin)
 Q_IMPORT_PLUGIN(QIbusPlatformInputContextPlugin)
 Q_IMPORT_PLUGIN(QFcitxPlatformInputContextPlugin)
+Q_IMPORT_PLUGIN(QHimePlatformInputContextPlugin)
 #endif // Q_OS_WIN | Q_OS_MAC | Q_OS_LINUX
diff --git a/Telegram/gyp/telegram_linux.gypi b/Telegram/gyp/telegram_linux.gypi
index b8866ec21..2c464928f 100644
--- a/Telegram/gyp/telegram_linux.gypi
+++ b/Telegram/gyp/telegram_linux.gypi
@@ -56,6 +56,7 @@
       'composeplatforminputcontextplugin',
       'ibusplatforminputcontextplugin',
       'fcitxplatforminputcontextplugin',
+      'himeplatforminputcontextplugin',
       'liblzma.a',
       'libopenal.a',
       'libavformat.a',