diff --git a/Makefile.am b/Makefile.am index 29212b1d..bff6e8f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,7 @@ SUBDIRS = \ gtk2 \ qt4 \ setup \ + x11 \ icons \ m4 \ po \ diff --git a/configure.ac b/configure.ac index a1506c87..fb750e4a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 3447e5d6..57c15239 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -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 diff --git a/x11/Makefile.am b/x11/Makefile.am index 0f2deb52..3b5ddfc5 100644 --- a/x11/Makefile.am +++ b/x11/Makefile.am @@ -1,97 +1,25 @@ -# vim:set noet ts=4: -# -# ibus - The Input Bus -# -# Copyright (c) 2007-2008 Huang Peng -# -# 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) +ibus_x11_CFLAGS = \ + @GTK2_CFLAGS@ \ + -I$(srcdir)/IMdkit \ + -I$(top_srcdir)/gtk2 \ $(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 \ - $(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 index 00000000..5f1cb12d --- /dev/null +++ b/x11/gdk-private.c @@ -0,0 +1,116 @@ +/* xim-on-gtkim + * Copyright (C) 2007 Huang Peng + * + * 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 +#include +#include + +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 index 00000000..886b6949 --- /dev/null +++ b/x11/gdk-private.h @@ -0,0 +1,28 @@ +/* xim-on-gtkim + * Copyright (C) 2007 Huang Peng + * + * 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 index 00000000..dd57f5da --- /dev/null +++ b/x11/main.c @@ -0,0 +1,693 @@ +/* xim-on-gtkim + * Copyright (C) 2007 Huang Peng + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCES +#include + +#define LOG(level, fmt, args...) \ + if (g_debug_level >= (level)) { \ + fprintf (stderr, fmt, args); \ + } + +#include +#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; + +}