Implement ibus xim agent.
authorHuang Peng <shawn.p.huang@gmail.com>
Wed, 23 Jul 2008 06:13:37 +0000 (14:13 +0800)
committerHuang Peng <shawn.p.huang@gmail.com>
Wed, 23 Jul 2008 06:13:37 +0000 (14:13 +0800)
Makefile.am
configure.ac
daemon/Makefile.am
x11/Makefile.am
x11/gdk-private.c [new file with mode: 0644]
x11/gdk-private.h [new file with mode: 0644]
x11/main.c [new file with mode: 0644]

index 29212b1dc3d375d08f3bfc042227cee66dbc3986..bff6e8f526fdbf653c0d118f1195fac2f06cb501 100644 (file)
@@ -29,6 +29,7 @@ SUBDIRS = \
        gtk2 \
        qt4 \
        setup \
+       x11 \
        icons \
        m4 \
        po \
index a1506c87edc379f7a31ecb92595ad68820a31c5d..fb750e4ad18cd9e1ff464cd9868f5578112ab4d7 100644 (file)
@@ -152,6 +152,8 @@ gconf/ibus-gconf
 engine/Makefile
 gtk2/Makefile
 qt4/Makefile
+x11/Makefile
+x11/IMdkit/Makefile
 setup/Makefile
 setup/ibus-setup
 setup/ibus-setup.desktop
index 3447e5d6e3968c715ac6a089aa4b987d62dd162a..57c152392d0f96666d5227f3a9aab1c0e7c1a0fc 100644 (file)
@@ -46,4 +46,4 @@ EXTRA_DIST = \
        $(NULL)
 
 test:
-       $(ENV) PYTHONPATH=$(top_srcdir) $(PYTHON) $(srcdir)/ibusdaemon.py
+       $(ENV) DBUS_DEBUG=true PYTHONPATH=$(top_srcdir) $(PYTHON) $(srcdir)/ibusdaemon.py
index 0f2deb5269c174745c100454e86e699b49761583..3b5ddfc5e5a0c2ab44710c8d225b18d96e525efc 100644 (file)
@@ -1,97 +1,25 @@
-# vim:set noet ts=4:
-#
-# ibus - The Input Bus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-# Boston, MA  02111-1307  USA
+bin_PROGRAMS = ibus-x11
 
-SUBDIRS = \
-       IMdkit \
+ibus_x11_SOURCES = \
+       main.c \
+       gdk-private.c \
        $(NULL)
 
-xim_PYTHON = \
-       engine.py \
-       factory.py \
-       main.py \
-       tables.py \
-       test.py \
+noinst_HEADERS = \
+       gdk-private.h \
        $(NULL)
 
-ximdir = $(datadir)/ibus/xim
+IMdkit = $(builddir)/IMdkit/libIMdkit.la
 
-IMdkit_DATA = \
-       IMdkit.py \
-       $(NULL)
-
-IMdkit_LTLIBRARIES = _IMdkit.la
-
-IMdkitdir = @pyexecdir@
-
-_IMdkit_la_SOURCES = \
-       $(NULL)
-
-nodist__IMdkit_la_SOURCES = \
-       IMdkit_wrap.c \
-       $(NULL)
-
-_IMdkit_la_CFLAGS = \
-       @X11_CFLAGS@ \
-       @GDK2_CFLAGS@ \
-       @PYGOBJECT2_CFLAGS@ \
-       @PYGTK2_CFLAGS@ \
-       @GTK2_CFLAGS@ \
-       @PYTHON_CFLAGS@ \
-       -IIMdkit \
-       $(NULL)
-
-_IMdkit_la_LDFLAGS = \
-       @X11_LIBS@ \
-       @GDK2_LIBS@ \
-       @PYGOBJECT2_LIBS@ \
-       @PYGTK2_LIBS@ \
+ibus_x11_LDADD = \
        @GTK2_LIBS@ \
-       @PYTHON_LIBS@ \
-       -rpath $(IMdkitdir) \
-       -avoid-version \
-       -module \
-       IMdkit/libIMdkit.la \
+       $(top_builddir)/gtk2/libibus-gtk.la \
+       $(IMdkit) \
        $(NULL)
-
-#libexec_SCRIPTS = ibus-xim
-
-IMdkit.py IMdkit_wrap.c: IMdkit.i
-       $(SWIG) -python -I/usr/include -o IMdkit_wrap.c $(srcdir)/IMdkit.i
-
-test: all
-       $(ENV) PYTHONPATH=$(builddir)/.libs python test.py
-
-test-ipython: all
-       $(ENV) PYTHONPATH=$(builddir)/.libs ipython
-
-EXTRA_DIST = \
-       IMdkit.i \
-       ibus-xim.in \
+ibus_x11_CFLAGS = \
+       @GTK2_CFLAGS@ \
+       -I$(srcdir)/IMdkit \
+       -I$(top_srcdir)/gtk2 \
        $(NULL)
 
-CLEANFILES = \
-       IMdkit.py \
-       IMdkit_wrap.* \
-       *.pyc \
-       $(MULL)
-
-DISTCLEANFILES = \
-       $(MULL)
+SUBDIRS = IMdkit 
diff --git a/x11/gdk-private.c b/x11/gdk-private.c
new file mode 100644 (file)
index 0000000..5f1cb12
--- /dev/null
@@ -0,0 +1,116 @@
+/* xim-on-gtkim
+ * Copyright (C) 2007 Huang Peng <phuang@redhat.com>
+ *
+ * gdk-private.c: Copied some code from gtk2
+ *
+ * This tool is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+
+void
+translate_key_event (GdkDisplay *display,
+                    GdkEvent   *event,
+                    XEvent     *xevent)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+  gunichar c = 0;
+  gchar buf[7];
+
+  event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+  event->key.time = xevent->xkey.time;
+
+  event->key.state = (GdkModifierType) xevent->xkey.state;
+  //event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
+  event->key.group = 0;
+  event->key.hardware_keycode = xevent->xkey.keycode;
+
+  event->key.keyval = GDK_VoidSymbol;
+
+  gdk_keymap_translate_keyboard_state (keymap,
+                                      event->key.hardware_keycode,
+                                      event->key.state,
+                                      event->key.group,
+                                      &event->key.keyval,
+                                      NULL, NULL, NULL);
+
+  //_gdk_keymap_add_virtual_modifiers (keymap, &event->key.state);
+  event->key.is_modifier = 
+       (event->key.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
+//  event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
+  /* Fill in event->string crudely, since various programs
+   * depend on it.
+   */
+  event->key.string = NULL;
+  
+  if (event->key.keyval != GDK_VoidSymbol)
+    c = gdk_keyval_to_unicode (event->key.keyval);
+
+  if (c)
+    {
+      gsize bytes_written;
+      gint len;
+
+      /* Apply the control key - Taken from Xlib
+       */
+      if (event->key.state & GDK_CONTROL_MASK)
+       {
+         if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+         else if (c == '2')
+           {
+             event->key.string = g_memdup ("\0\0", 2);
+             event->key.length = 1;
+             buf[0] = '\0';
+             goto out;
+           }
+         else if (c >= '3' && c <= '7') c -= ('3' - '\033');
+         else if (c == '8') c = '\177';
+         else if (c == '/') c = '_' & 0x1F;
+       }
+      
+      len = g_unichar_to_utf8 (c, buf);
+      buf[len] = '\0';
+      
+      event->key.string = g_locale_from_utf8 (buf, len,
+                                             NULL, &bytes_written,
+                                             NULL);
+      if (event->key.string)
+       event->key.length = bytes_written;
+    }
+  else if (event->key.keyval == GDK_Escape)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\033");
+    }
+  else if (event->key.keyval == GDK_Return ||
+         event->key.keyval == GDK_KP_Enter)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\r");
+    }
+
+  if (!event->key.string)
+    {
+      event->key.length = 0;
+      event->key.string = g_strdup ("");
+    }
+  
+ out:
+  return;
+}
+
diff --git a/x11/gdk-private.h b/x11/gdk-private.h
new file mode 100644 (file)
index 0000000..886b694
--- /dev/null
@@ -0,0 +1,28 @@
+/* xim-on-gtkim
+ * Copyright (C) 2007 Huang Peng <phuang@redhat.com>
+ *
+ * gdk-private.h:
+ *
+ * This tool is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRIVATE_H_
+#define __GTK_PRIVATE_H_
+
+void
+translate_key_event (GdkDisplay *display,
+                    GdkEvent   *event,
+                    XEvent     *xevent);
+#endif
diff --git a/x11/main.c b/x11/main.c
new file mode 100644 (file)
index 0000000..dd57f5d
--- /dev/null
@@ -0,0 +1,693 @@
+/* xim-on-gtkim
+ * Copyright (C) 2007 Huang Peng <phuang@redhat.com>
+ *
+ * main.c:
+ *
+ * This tool is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include <XimProto.h>
+#include <IMdkit.h>
+#include <Xi18n.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <iconv.h>
+
+#define _GNU_SOURCES
+#include <getopt.h>
+
+#define LOG(level, fmt, args...)       \
+       if (g_debug_level >= (level)) { \
+       fprintf (stderr, fmt, args);    \
+       }
+
+#include <ibusimclient.h>
+#include "gdk-private.h"
+
+struct _X11ICONN {
+       GList           *clients;
+};
+typedef struct _X11ICONN       X11ICONN;
+
+struct _X11IC {
+       GtkIMContext *context;
+       GdkWindow       *client_window;
+       GdkWindow       *focus_window;
+       gint32          input_style;
+       X11ICONN        *conn;
+       gint            icid;
+       gint            connect_id;
+       gchar           *lang;
+       GdkRectangle    preedit_area;
+};
+typedef struct _X11IC  X11IC;
+
+
+
+static void _xim_commit_cb (GtkIMContext *context, gchar *arg, gpointer data);
+
+static GHashTable      *g_clients = NULL;
+static GHashTable      *g_connections = NULL;
+static XIMS            g_xims = NULL;
+static gchar           g_server_name[128] = "ibus";
+static gchar           g_locale[1024] = 
+       "aa,af,am,an,ar,as,az,be,bg,bn,br,bs,"
+       "ca,cs,cy,da,de,dz,el,en,es,et,eu,"
+       "fa,fi,fo,fr,fy,ga,gd,gl,gu,gv,"
+       "he,hi,hr,hu,hy,id,is,it,iw,ja,"
+       "ka,kk,kl,km,kn,ko,ku,kw,ky,lg,lo,lt,lv,"
+       "mg,mi,mk,ml,mn,mr,ms,mt,nb,ne,nl,nn,no,nr,"
+       "oc,om,or,pa,pl,pt,ro,ru,rw,"
+       "se,si,sk,sl,so,sq,sr,ss,st,sv,"
+       "ta,te,tg,th,ti,tl,tn,tr,ts,tt,"
+       "uk,ur,uz,ve,vi,wa,xh,yi,zh,zu";
+
+static gint            g_debug_level = 0;
+
+IBusIMClient *_client = NULL;
+
+
+static void
+_xim_preedit_start (XIMS xims, int icid, int connect_id)
+{
+       IMPreeditStateStruct ips;
+       ips.major_code = 0;
+       ips.minor_code = 0;
+       ips.icid = icid;
+       ips.connect_id = connect_id;
+       IMPreeditStart (xims, (XPointer)&ips);
+}
+
+static void
+_xim_preedit_end (XIMS xims, int icid, int connect_id)
+{
+       IMPreeditStateStruct ips;
+       ips.major_code = 0;
+       ips.minor_code = 0;
+       ips.icid = icid;
+       ips.connect_id = connect_id;
+       IMPreeditEnd (xims, (XPointer)&ips);
+}
+
+int
+_xim_store_ic_values (X11IC *ic, IMChangeICStruct *call_data)
+{
+       XICAttribute *ic_attr = call_data->ic_attr;
+       XICAttribute *pre_attr = call_data->preedit_attr;
+       XICAttribute *sts_attr = call_data->status_attr;
+
+       gint i;
+       guint32 attrs = 1;
+       
+       if (ic == NULL) {
+               return 0;
+       }
+#define _is_attr(a, b) (strcmp(a, b->name) == 0)
+       for (i=0; i< (int) call_data->ic_attr_num; ++i, ++ic_attr) {
+               if (_is_attr (XNInputStyle, ic_attr)) {
+                       ic->input_style = *(gint32 *) ic_attr->value;
+               }
+               else if (_is_attr (XNClientWindow, ic_attr)) {
+                       Window w;
+                       
+                       if (ic->client_window != NULL) {
+                               g_object_unref (ic->client_window);
+                       }
+                       
+                       w =  *(Window *) call_data->ic_attr[i].value;
+                       ic->client_window = gdk_window_foreign_new (w);
+               }
+               else if (_is_attr (XNFocusWindow, ic_attr)) {
+                       Window w;
+                       
+                       if (ic->focus_window != NULL) {
+                               g_object_unref (ic->focus_window);
+                       }
+
+                       w =  *(Window *) call_data->ic_attr[i].value;
+                       ic->focus_window = gdk_window_foreign_new (w);
+               }
+               else {
+                       // fprintf (stderr, "Unknown attr: %s\n", ic_attr->name);
+               }
+       }
+
+       for (i=0; i< (int) call_data->preedit_attr_num; ++i, ++pre_attr) {
+               if (_is_attr (XNSpotLocation, pre_attr)) {
+                       ic->preedit_area.x = ((XPoint *)pre_attr->value)->x;
+                       ic->preedit_area.y = ((XPoint *)pre_attr->value)->y;
+               }
+               else {
+                       // fprintf (stderr, "Unknown attr: %s\n", pre_attr->name);
+               }
+       }
+       
+       for (i=0; i< (int) call_data->status_attr_num; ++i, ++sts_attr) {
+               // printf ("set status: %s\n", sts_attr->name);
+       }
+
+#undef _is_attr
+
+       return attrs;
+
+}
+
+
+static void
+_xim_commit_cb (GtkIMContext *context, gchar *arg, gpointer data)
+{
+       char *clist[1];
+       XTextProperty tp;
+       IMCommitStruct cms;
+       
+       X11IC *ic = (X11IC *)data;
+
+       clist[0] = arg;
+       Xutf8TextListToTextProperty (GDK_DISPLAY (), clist, 1, XCompoundTextStyle, &tp);
+       
+       memset (&cms, 0, sizeof (cms));
+       cms.major_code = XIM_COMMIT;
+       cms.icid = ic->icid;
+       cms.connect_id = ic->connect_id;
+       cms.flag = XimLookupChars;
+       cms.commit_string = (char *)tp.value;
+       IMCommitString (g_xims, (XPointer) & cms);
+       
+       XFree (tp.value);
+
+}
+
+
+int
+xim_create_ic (XIMS xims, IMChangeICStruct *call_data)
+{
+       static int base_icid = 1;
+       X11IC *ic;
+       int i;
+
+       LOG (1, "XIM_CREATE_IC ic=%d, connect_id=%d\n", call_data->icid, call_data->connect_id);
+
+       call_data->icid = base_icid ++;
+       
+       ic = g_malloc0 (sizeof (X11IC));
+       ic->icid = call_data->icid;
+       ic->connect_id = call_data->connect_id;
+       ic->conn = (X11ICONN *)g_hash_table_lookup (g_connections,
+                                               (gconstpointer)(unsigned long)call_data->connect_id);
+
+       
+       i = _xim_store_ic_values (ic, call_data);
+       
+       ic->context = (GtkIMContext *)ibus_im_client_create_im_context (_client);
+       gtk_im_context_set_client_window (ic->context, ic->client_window);
+       gtk_im_context_set_use_preedit (ic->context, FALSE);
+       g_signal_connect (ic->context, 
+                       "commit", 
+                       G_CALLBACK (_xim_commit_cb), 
+                       (gpointer)ic);
+
+
+       g_hash_table_insert (g_clients, (gpointer)ic->icid, (gpointer) ic);
+       ic->conn->clients = g_list_append (ic->conn->clients, (gpointer) ic);
+       
+       return 1;
+}
+
+
+int
+xim_destroy_ic (XIMS xims, IMChangeICStruct *call_data)
+{
+       X11IC *ic;
+       
+       LOG (1, "XIM_DESTROY_IC ic=%d, connect_id=%d\n", call_data->icid, call_data->connect_id);
+       
+       ic = (X11IC *)g_hash_table_lookup (g_clients,
+                               (gconstpointer)(unsigned long)call_data->icid);
+       g_object_unref (ic->context);
+       ic->conn->clients = g_list_remove (ic->conn->clients, (gconstpointer)ic);
+       g_hash_table_remove (g_clients,
+                               (gconstpointer)(unsigned long)call_data->icid);
+
+       g_free (ic);
+
+       return 1;
+}
+
+int
+xim_set_ic_focus (XIMS xims, IMChangeFocusStruct *call_data)
+{
+       X11IC *ic;
+       
+       LOG (1, "XIM_SET_IC_FOCUS ic=%d, connect_id=%d\n", call_data->icid, call_data->connect_id);
+       
+       ic = (X11IC *)g_hash_table_lookup (g_clients,
+                               (gconstpointer)(unsigned long)call_data->icid);
+
+       gtk_im_context_focus_in (ic->context);
+
+       return 1;
+
+}
+
+int
+xim_unset_ic_focus (XIMS xims, IMChangeFocusStruct *call_data)
+{      
+       X11IC *ic;
+       
+       LOG (1, "XIM_UNSET_IC_FOCUS ic=%d, connect_id=%d\n", call_data->icid, call_data->connect_id);
+       
+       ic = (X11IC *)g_hash_table_lookup (g_clients,
+                       (gconstpointer)(unsigned long)call_data->icid);
+       
+       gtk_im_context_focus_out (ic->context);
+
+       return 1;
+
+}
+
+int
+xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
+{
+               
+       X11IC *ic;
+       XKeyEvent *xevent;
+       GdkEventKey event;
+       GdkWindow *window;
+
+       ic = (X11IC *)g_hash_table_lookup (g_clients,
+                               (gconstpointer)(unsigned long)call_data->icid);
+
+       g_return_val_if_fail (ic != NULL, 1);
+
+       window = ic->focus_window != NULL ? ic->focus_window : ic->client_window;
+
+       xevent = (XKeyEvent*) &(call_data->event);
+
+       translate_key_event (gdk_drawable_get_display (window), 
+               (GdkEvent *)&event, (XEvent *)xevent);
+
+       event.send_event = xevent->send_event;
+       event.window = window;
+
+       if (gtk_im_context_filter_keypress (ic->context, &event)) {
+               return 1;
+       }
+       else {
+               IMForwardEventStruct fe;
+               XEvent xkp;
+               XKeyEvent *event = (XKeyEvent*) (&xkp);
+               
+               memset (&fe, 0, sizeof (fe));
+               fe.major_code = XIM_FORWARD_EVENT;
+               fe.icid = ic->icid;
+               fe.connect_id = ic->connect_id;
+               fe.sync_bit = 0;
+               fe.serial_number = 0L;
+               fe.event = call_data->event;
+               IMForwardEvent (g_xims, (XPointer) & fe);
+               return 1;
+       }
+}
+
+
+int
+xim_open (XIMS xims, IMOpenStruct *call_data)
+{
+       X11ICONN *conn;
+       gchar *last;
+       
+       LOG (1, "XIM_OPEN connect_id=%d\n", call_data->connect_id);
+       
+       conn = (X11ICONN *)g_hash_table_lookup (g_connections, 
+                               (gconstpointer)(unsigned long)call_data->connect_id);
+       
+       g_return_val_if_fail (conn == NULL, 1);
+       
+       conn = (X11ICONN *) g_malloc0(sizeof (X11ICONN));
+       // conn->context = GTK_IM_CONTEXT (gtk_im_multicontext_new ());
+               
+       g_hash_table_insert (g_connections, 
+               (gpointer)(unsigned long)call_data->connect_id, 
+               (gpointer) conn);
+       
+       // g_signal_connect_after (conn->context, 
+       //              "commit", 
+       //              G_CALLBACK (_xim_commit_cb), 
+       //              (gpointer)(unsigned long)call_data->connect_id);
+
+       return 1;
+}
+
+static void
+_free_ic (gpointer data, gpointer user_data)
+{
+       X11IC *ic = (X11IC *) data;
+
+       g_return_if_fail (ic != NULL);
+
+       g_object_unref (ic->context);
+
+       /* Remove the IC from g_client dictionary */
+       g_hash_table_remove (g_clients,
+                               (gconstpointer)(unsigned long)ic->icid);
+
+       g_free (ic);
+}
+
+int
+xim_close (XIMS ims, IMCloseStruct *call_data)
+{
+       X11ICONN *conn;
+
+       LOG (1, "XIM_CLOSE connect_id=%d\n", call_data->connect_id);
+       
+       conn = (X11ICONN *)g_hash_table_lookup (g_connections, 
+                               (gconstpointer)(unsigned long)call_data->connect_id);
+
+       g_return_val_if_fail (conn != NULL, 1);
+       
+       g_list_foreach (conn->clients, _free_ic, NULL);
+
+       g_list_free (conn->clients);
+
+       // g_object_unref (conn->context);
+
+       g_hash_table_remove (g_connections, (gconstpointer)(unsigned long)call_data->connect_id);
+
+       g_free (conn);
+       
+       return 1;
+}
+
+
+
+int
+xim_set_ic_values (XIMS xims, IMChangeICStruct *call_data)
+{
+       X11IC *ic;
+       gint i;
+       
+       LOG (1, "XIM_SET_IC_VALUES ic=%d connect_id=%d\n", call_data->icid, call_data->connect_id);
+       
+       ic = (X11IC *)g_hash_table_lookup (g_clients, 
+                               (gconstpointer)(unsigned long)call_data->icid);
+
+       g_return_val_if_fail (ic != NULL, 1);
+
+       i = _xim_store_ic_values (ic, call_data);
+
+       if (i) {
+               gtk_im_context_set_cursor_location (ic->context, &ic->preedit_area);
+       }
+
+       return i;
+}
+
+
+int
+xim_reset_ic (XIMS xims, IMResetICStruct *call_data)
+{
+       X11IC *ic;
+       
+       LOG (1, "XIM_RESET_IC ic=%d connect_id=%d\n", call_data->icid, call_data->connect_id);
+       
+       ic = (X11IC *)g_hash_table_lookup (g_clients, 
+                               (gconstpointer)(unsigned long)call_data->icid);
+
+       g_return_val_if_fail (ic != NULL, 1);
+
+       gtk_im_context_reset (ic->context);
+
+       return 1;
+}
+
+int
+ims_protocol_handler (XIMS xims, IMProtocol *call_data)
+{
+       g_return_val_if_fail (xims != NULL, 1);
+       g_return_val_if_fail (call_data != NULL, 1);
+       
+       switch (call_data->major_code) {
+       case XIM_OPEN:
+               return xim_open (xims, (IMOpenStruct *)call_data);
+       case XIM_CLOSE:
+               return xim_close (xims, (IMCloseStruct *)call_data);
+       case XIM_CREATE_IC:
+               return xim_create_ic (xims, (IMChangeICStruct *)call_data);
+       case XIM_DESTROY_IC: 
+               return xim_destroy_ic (xims, (IMChangeICStruct *)call_data);
+       case XIM_SET_IC_VALUES: 
+               return xim_set_ic_values (xims, (IMChangeICStruct *)call_data);
+       case XIM_GET_IC_VALUES:
+               return 1;
+       case XIM_FORWARD_EVENT:
+               return xim_forward_event (xims, (IMForwardEventStruct *)call_data);
+       case XIM_SET_IC_FOCUS:
+               return xim_set_ic_focus (xims, (IMChangeFocusStruct *)call_data);
+       case XIM_UNSET_IC_FOCUS:
+               return xim_unset_ic_focus (xims, (IMChangeFocusStruct *)call_data);
+       case XIM_RESET_IC:
+               return xim_reset_ic (xims, (IMResetICStruct *)call_data);
+       case XIM_TRIGGER_NOTIFY:
+       case XIM_PREEDIT_START_REPLY:
+       case XIM_PREEDIT_CARET_REPLY:
+       case XIM_SYNC_REPLY: 
+               return 1;
+       default:
+               break;
+       }
+       return 1;
+}
+
+
+#if 0
+static void
+_xim_forward_gdk_event (GdkEventKey *event)
+{
+       IMForwardEventStruct fe;
+       XEvent xkp;
+       memset (&xkp, 0, sizeof (xkp));
+       memset (&fe, 0, sizeof (fe));
+
+       xkp.xkey.type = (event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
+       xkp.xkey.serial = 0L;
+       xkp.xkey.send_event = False;
+       xkp.xkey.same_screen = False;
+       xkp.xkey.display = GDK_WINDOW_XDISPLAY (event->window);
+       xkp.xkey.window = GDK_WINDOW_XWINDOW (event->window);
+       xkp.xkey.subwindow = None;
+       xkp.xkey.root = DefaultRootWindow (GDK_WINDOW_XDISPLAY (event->window));
+       xkp.xkey.time = event->time;
+       xkp.xkey.state = event->state;
+       xkp.xkey.keycode = event->hardware_keycode;
+
+       fe.major_code = XIM_FORWARD_EVENT;
+       fe.icid = g_focus_ic->icid;
+       fe.connect_id = g_focus_ic->connect_id;
+       fe.sync_bit = 0;
+       fe.serial_number = 0L;
+       fe.event = xkp;
+       IMForwardEvent (g_xims, (XPointer) & fe);
+
+}
+#endif
+
+static void
+_xim_event_cb (GdkEvent *event, gpointer data)
+{
+       switch (event->type) {
+       case GDK_KEY_PRESS:
+       case GDK_KEY_RELEASE:
+               //_xim_forward_gdk_event ((GdkEventKey *)event);
+               break;
+       default:
+               gtk_main_do_event (event);
+               break;
+       }
+}
+
+static void
+_xim_event_destroy_cb (gpointer data)
+{
+}
+
+static void
+_xim_init_IMdkit ()
+{
+       XIMStyle ims_styles_overspot [] = {
+               XIMPreeditPosition  | XIMStatusNothing,
+               XIMPreeditNothing   | XIMStatusNothing,
+               XIMPreeditPosition  | XIMStatusCallbacks,
+               XIMPreeditNothing   | XIMStatusCallbacks,
+               0
+       };
+
+       XIMStyle ims_styles_onspot [] = {
+               XIMPreeditPosition  | XIMStatusNothing,
+               XIMPreeditCallbacks | XIMStatusNothing,
+               XIMPreeditNothing   | XIMStatusNothing,
+               XIMPreeditPosition  | XIMStatusCallbacks,
+               XIMPreeditCallbacks | XIMStatusCallbacks,
+               XIMPreeditNothing   | XIMStatusCallbacks,
+               0
+       };
+
+       XIMEncoding ims_encodings[] = {
+               "COMPOUND_TEXT",
+               0
+       };
+
+       GdkWindowAttr window_attr = {
+               title :         "xim2gtkim",
+               event_mask :    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+               wclass:         GDK_INPUT_OUTPUT,
+               window_type:    GDK_WINDOW_TOPLEVEL,
+               override_redirect: 1,
+       };
+
+       XIMStyles styles;
+       XIMEncodings encodings;
+
+       GdkWindow *win;
+
+       win = gdk_window_new (NULL, &window_attr, GDK_WA_TITLE);
+       
+       styles.count_styles = 
+               sizeof (ims_styles_onspot)/sizeof (XIMStyle) - 1;
+       styles.supported_styles = ims_styles_onspot;
+
+       encodings.count_encodings = 
+               sizeof (ims_encodings)/sizeof (XIMEncoding) - 1;
+       encodings.supported_encodings = ims_encodings;
+       
+       g_xims = IMOpenIM(GDK_DISPLAY(),
+               IMModifiers, "Xi18n",
+               IMServerWindow, GDK_WINDOW_XWINDOW(win),
+               IMServerName, g_server_name,
+               IMLocale, g_locale,
+               IMServerTransport, "X/",
+               IMInputStyles, &styles,
+               IMEncodingList, &encodings,
+               IMProtocolHandler, ims_protocol_handler,
+               IMFilterEventMask, KeyPressMask | KeyReleaseMask,
+               NULL);
+
+       gdk_event_handler_set (_xim_event_cb, NULL, 
+               _xim_event_destroy_cb);
+
+       ibus_im_client_register_type (NULL);
+       ibus_im_context_register_type (NULL);
+       _client = ibus_im_client_new ();
+
+}
+
+static void
+print_usage (FILE *fp, gchar *name)
+{
+       fprintf (fp, 
+               "Usage:\n"
+               " %s --help               Show this message\n"
+               "    --server-name= -n    Setup xim sevrer name\n"
+               "    --locale= -l         Setup support locale\n"
+               "    --debug= -v          Setup debug level\n",
+               name);
+}
+
+
+int main (int argc, char **argv)
+{
+       GMainLoop *loop;
+       gint option_index = 0;
+       gint c;
+
+       gdk_init (&argc, &argv);
+
+       while (1) {
+               static struct option long_options [] = {
+                       {"debug", 1, 0, 0},
+                       {"server-name", 1, 0, 0},
+                       {"locale", 1, 0, 0},
+                       {"help", 0, 0, 0},
+                       {0, 0, 0, 0},
+               };
+
+               c = getopt_long (argc, argv, "v:n:l:",
+                       long_options, &option_index);
+
+               if (c == -1) break;
+
+               switch (c) {
+               case 0:
+                       if (strcmp (long_options[option_index].name, "debug") == 0) {
+                               g_debug_level = atoi (optarg);
+                       }
+                       else if (strcmp (long_options[option_index].name, "server-name") == 0) {
+                               strncpy (g_server_name, optarg, sizeof (g_server_name));
+                       }
+                       else if (strcmp (long_options[option_index].name, "locale") == 0) {
+                               strncpy (g_locale, optarg, sizeof (g_locale));
+                       }
+                       else if (strcmp (long_options[option_index].name, "help") == 0) {
+                               print_usage (stdout, argv[0]);
+                               exit (EXIT_SUCCESS);
+                       }
+                       break;
+               case 'v':
+                       g_debug_level = atoi (optarg);
+                       break;
+               case 'n':
+                       strncpy (g_server_name, optarg, sizeof (g_server_name));
+                       break;
+               case 'l':
+                       strncpy (g_locale, optarg, sizeof (g_locale));
+                       break;
+               case '?':
+               default:
+                       print_usage (stderr, argv[0]);
+                       exit (EXIT_FAILURE);
+               }
+                       
+
+       }
+
+       g_clients = g_hash_table_new (g_direct_hash, g_direct_equal);
+       g_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+       printf ("server-name = %s\n", g_server_name);
+       printf ("locale      = %s\n", g_locale);
+
+       _xim_init_IMdkit ();
+
+
+       loop = g_main_loop_new (NULL, TRUE);
+
+       if (g_main_loop_is_running (loop)) {
+               GDK_THREADS_LEAVE ();
+               g_main_loop_run (loop);
+               GDK_THREADS_ENTER ();
+               gdk_flush ();
+       }
+
+       return 0;
+
+}