+ return 0;
+}
+
+\f
+
+/* XIM (X Input Method) handler */
+
+typedef struct MInputXIMMethodInfo
+{
+ Display *display;
+ XIM xim;
+ MSymbol language;
+ MSymbol coding;
+} MInputXIMMethodInfo;
+
+typedef struct MInputXIMContextInfo
+{
+ XIC xic;
+ Window win;
+ MConverter *converter;
+} MInputXIMContextInfo;
+
+static int
+xim_open_im (MInputMethod *im)
+{
+ MInputXIMArgIM *arg = (MInputXIMArgIM *) im->arg;
+ MLocale *saved, *this;
+ char *save_modifier_list;
+ XIM xim;
+ MInputXIMMethodInfo *im_info;
+
+ saved = mlocale_set (LC_CTYPE, NULL);
+ this = mlocale_set (LC_CTYPE, arg->locale ? arg->locale : "");
+ if (! this)
+ /* The specified locale is not supported. */
+ MERROR (MERROR_LOCALE, -1);
+ if (mlocale_get_prop (this, Mcoding) == Mnil)
+ {
+ /* Unable to decode the output of XIM. */
+ mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
+ MERROR (MERROR_LOCALE, -1);
+ }
+
+ if (arg->modifier_list)
+ save_modifier_list = XSetLocaleModifiers (arg->modifier_list);
+ else
+ save_modifier_list = XSetLocaleModifiers ("");
+ if (! save_modifier_list)
+ {
+ /* The specified locale is not supported by X. */
+ mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
+ MERROR (MERROR_LOCALE, -1);
+ }
+
+ xim = XOpenIM (arg->display, arg->db, arg->res_name, arg->res_class);
+ if (! xim)
+ {
+ /* No input method is available in the current locale. */
+ XSetLocaleModifiers (save_modifier_list);
+ mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
+ MERROR (MERROR_WIN, -1);
+ }
+
+ MSTRUCT_MALLOC (im_info, MERROR_WIN);
+ im_info->display = arg->display;
+ im_info->xim = xim;
+ im_info->language = mlocale_get_prop (this, Mlanguage);
+ im_info->coding = mlocale_get_prop (this, Mcoding);
+ im->info = im_info;
+
+ XSetLocaleModifiers (save_modifier_list);
+ mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
+
+ return 0;
+}
+
+static void
+xim_close_im (MInputMethod *im)
+{
+ MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) im->info;
+
+ XCloseIM (im_info->xim);
+ free (im_info);
+}
+
+static int
+xim_create_ic (MInputContext *ic)
+{
+ MInputXIMArgIC *arg = (MInputXIMArgIC *) ic->arg;
+ MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
+ MInputXIMContextInfo *ic_info;
+ XIC xic;
+
+ if (! arg->input_style)
+ {
+ /* By default, use Root style. */
+ arg->input_style = XIMPreeditNothing | XIMStatusNothing;
+ arg->preedit_attrs = NULL;
+ arg->status_attrs = NULL;
+ }
+
+ if (! arg->preedit_attrs && ! arg->status_attrs)
+ xic = XCreateIC (im_info->xim,
+ XNInputStyle, arg->input_style,
+ XNClientWindow, arg->client_win,
+ XNFocusWindow, arg->focus_win,
+ NULL);
+ else if (arg->preedit_attrs && ! arg->status_attrs)
+ xic = XCreateIC (im_info->xim,
+ XNInputStyle, arg->input_style,
+ XNClientWindow, arg->client_win,
+ XNFocusWindow, arg->focus_win,
+ XNPreeditAttributes, arg->preedit_attrs,
+ NULL);
+ else if (! arg->preedit_attrs && arg->status_attrs)
+ xic = XCreateIC (im_info->xim,
+ XNInputStyle, arg->input_style,
+ XNClientWindow, arg->client_win,
+ XNFocusWindow, arg->focus_win,
+ XNStatusAttributes, arg->status_attrs,
+ NULL);
+ else
+ xic = XCreateIC (im_info->xim,
+ XNInputStyle, arg->input_style,
+ XNClientWindow, arg->client_win,
+ XNFocusWindow, arg->focus_win,
+ XNPreeditAttributes, arg->preedit_attrs,
+ XNStatusAttributes, arg->status_attrs,
+ NULL);
+ if (! xic)
+ MERROR (MERROR_WIN, -1);
+
+ MSTRUCT_MALLOC (ic_info, MERROR_WIN);
+ ic_info->xic = xic;
+ ic_info->win = arg->focus_win;
+ ic_info->converter = mconv_buffer_converter (im_info->coding, NULL, 0);
+ ic->info = ic_info;
+ return 0;
+}
+
+static void
+xim_destroy_ic (MInputContext *ic)
+{
+ MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
+
+ XDestroyIC (ic_info->xic);
+ mconv_free_converter (ic_info->converter);
+ free (ic_info);
+ ic->info = NULL;
+}
+
+static int
+xim_filter (MInputContext *ic, MSymbol key, void *event)
+{
+ MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
+
+ return (XFilterEvent ((XEvent *) event, ic_info->win) == True);
+}
+
+
+static int
+xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
+{
+ MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
+ MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
+ XKeyPressedEvent *ev = (XKeyPressedEvent *) arg;
+ KeySym keysym;
+ Status status;
+ char *buf;
+ int len;
+
+ buf = (char *) alloca (512);
+ len = XmbLookupString (ic_info->xic, ev, buf, 512, &keysym, &status);
+ if (status == XBufferOverflow)
+ {
+ buf = (char *) alloca (len);
+ len = XmbLookupString (ic_info->xic, ev, buf, len, &keysym, &status);
+ }
+
+ mtext_reset (ic->produced);
+ if (len == 0)
+ return 1;