This commit was generated by cvs2svn to compensate for changes in r1705,
[chise/xemacs-chise.git.1] / src / input-method-xlib.c
1 /* Various functions for X11R5+ input methods, using the Xlib interface.
2    Copyright (C) 1996 Sun Microsystems.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: Not in FSF. */
22
23 /* Written by Martin Buchholz. */
24
25 /* This file implements an interface to X input methods, available
26    with X11R5 and above.  See O'Reilly, Xlib programmer's guide,
27    and X11 R6 release guide chapters on internationalized input,
28    for further details */
29
30 /*
31   Policy:
32
33   The XIM is of the device, by the device, for the device.
34   The XIC is of each frame, by each frame, for each frame.
35   The exceptions are:
36       1.  Activate XICs on poor frames when the XIM is back.
37       2.  Deactivate all the XICs when the XIM go down.
38
39   Methods:
40
41     -  Register a callback for an XIM when the X device is being initialized.
42        XIM_init_device (d) { XRegisterIMInstantiateCallback (); }
43        The "XRegisterIMInstantiateCallback" is called when an XIM become
44        available on the X display.
45
46     -  Catch the XIC when the frame is being initialized if XIM was available.
47        XIM_init_frame (f) { ... XCreateIC (); ... }
48
49     -  Release the XIC when the frame is being closed.
50        XIM_delete_frame (f) { ... FRAME_X_XIC (f) = NULL; ... }
51        "XIM_delete_frame" is a "DestroyCallback" function declared in
52        XIM_init_frame ();
53
54     -  Release all the XICs when the XIM was down accidentally.
55        In IMDestroyCallback:
56            DEVICE_FRAME_LOOP (...) { FRAME_X_XIC (f) = NULL; }
57
58     -  Re-enable XIC for all the frames which doesn't have XIC when the XIM
59        is back.
60        In IMInstantiateCallback:
61            DEVICE_FRAME_LOOP (...) { XIM_init_frame (f); }
62
63
64   Note:
65
66     -  Currently, we don't use XDestroyIC because of _XimProtoCloseIM
67        (internally registered as im->methods->close) does "Xfree (ic)".
68
69  */
70
71 #include <config.h>
72 #include "lisp.h"
73 #include <X11/Xlocale.h>        /* More portable than <locale.h> ? */
74 #include "frame.h"
75 #include "device.h"
76 #include "window.h"
77 #include "buffer.h"
78 #include "console-x.h"
79 #include "EmacsFrame.h"
80 #include "events.h"
81
82 #ifdef THIS_IS_X11R6
83 #include <X11/IntrinsicP.h>
84 #endif
85
86 #ifndef XIM_XLIB
87 #error  XIM_XLIB is not defined??
88 #endif
89
90 Lisp_Object Qxim_xlib;
91 #define xim_warn(str) warn_when_safe (Qxim_xlib, Qwarning, str);
92 #define xim_warn1(fmt, str) warn_when_safe (Qxim_xlib, Qwarning, fmt, str);
93 #define xim_info(str) warn_when_safe (Qxim_xlib, Qinfo, str);
94
95 /* Get/Set IC values for just one attribute */
96 #ifdef DEBUG_XEMACS
97 #define XIC_Value(Get_Set, xic, name, attr, value)                      \
98 do {                                                                    \
99   char *bad_arg;                                                        \
100   XVaNestedList list = XVaCreateNestedList (0, attr, value, NULL);      \
101   if ((bad_arg = X##Get_Set##ICValues (xic, name, list, NULL)) != NULL) \
102     stderr_out ("X" #Get_Set "ICValues " "bad Arg: %s\n", bad_arg);     \
103   XFree (list);                                                         \
104 } while (0)
105 #else /* ! DEBUG_XEMACS */
106 #define XIC_Value(Get_Set, xic, name, attr, value)                      \
107 do {                                                                    \
108   XVaNestedList list = XVaCreateNestedList (0, attr, value, NULL);      \
109   X##Get_Set##ICValues (xic, name, list, NULL);                         \
110   XFree (list);                                                         \
111 } while (0)
112 #endif /* DEBUG_XEMACS */
113
114 static char DefaultXIMStyles[] =
115 "XIMPreeditPosition|XIMStatusArea\n"
116 "XIMPreeditPosition|XIMStatusNone\n"
117 "XIMPreeditPosition|XIMStatusNothing\n"
118 "XIMPreeditNothing|XIMStatusArea\n"
119 "XIMPreeditNothing|XIMStatusNothing\n"
120 "XIMPreeditNothing|XIMStatusNone\n"
121 "XIMPreeditNone|XIMStatusArea\n"
122 "XIMPreeditNone|XIMStatusNothing\n"
123 "XIMPreeditNone|XIMStatusNone";
124
125 static Boolean xim_initted = False;
126
127 static XIMStyle best_style (XIMStyles *user, XIMStyles *xim);
128
129 /* #### it appears this prototype is missing from the X11R6.4 includes,
130    at least the XFree86 version ... */
131 char * XSetIMValues(XIM, ...);
132
133 void
134 Initialize_Locale (void)
135 {
136   char *locale;
137
138   /* dverna - Nov. 98: #### DON'T DO THIS !!! The default XtLanguageProc
139      routine calls setlocale(LC_ALL, lang) which fucks up our lower-level
140      locale management, and especially the value of LC_NUMERIC. Anyway, since
141      at this point, we don't know yet whether we're gonna need an X11 frame,
142      we should really do it manually and not use Xlib's dumb default routine */
143   /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/
144   if ((locale = setlocale (LC_ALL, "")) == NULL)
145     {
146       xim_warn ("Can't set locale.\n"
147                 "Using C locale instead.\n");
148       putenv ("LANG=C");
149       putenv ("LC_ALL=C");
150       if ((locale = setlocale (LC_ALL, "C")) == NULL)
151         {
152           xim_warn ("Can't even set locale to `C'!\n");
153           return;
154         }
155     }
156
157   if (!XSupportsLocale ())
158     {
159       xim_warn1 ("X Windows does not support locale `%s'\n"
160                  "Using C Locale instead\n", locale);
161       putenv ("LANG=C");
162       putenv ("LC_ALL=C");
163       if ((locale = setlocale (LC_ALL, "C")) == NULL)
164         {
165           xim_warn ("Can't even set locale to `C'!\n");
166           return;
167         }
168       if (!XSupportsLocale ())
169         {
170           xim_warn ("X Windows does not even support locale `C'!\n");
171           return;
172         }
173     }
174
175   setlocale(LC_NUMERIC, "C");
176
177   if (XSetLocaleModifiers ("") == NULL)
178     {
179       xim_warn ("XSetLocaleModifiers(\"\") failed\n"
180                 "Check the value of the XMODIFIERS environment variable.\n");
181     }
182 }
183
184 #ifdef THIS_IS_X11R6 /* Callbacks for IM are supported from X11R6 or later. */
185 /* Called from when XIM is destroying.
186    Clear all the XIC when the XIM was destroying... */
187 static void
188 IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data)
189 {
190   struct device *d = (struct device *)client_data;
191   Lisp_Object tail;
192
193   DEVICE_FRAME_LOOP (tail, d)
194     {
195       struct frame *target_frame = XFRAME (XCAR (tail));
196       if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame))
197         {
198           /* XDestroyIC (FRAME_X_XIC (target_frame)); */
199           FRAME_X_XIC (target_frame) = NULL;
200         }
201     }
202
203   DEVICE_X_XIM (d) = NULL;
204   xim_initted = False;
205   return;
206 }
207
208 /* This is registered in XIM_init_device (when DEVICE is initializing).
209    This activates XIM when XIM becomes available. */
210 static void
211 IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
212 {
213   struct device *d = (struct device *)client_data;
214   XIM xim;
215   char *name, *class;
216   XIMCallback ximcallback;
217   Lisp_Object tail;
218
219   /* if no xim is presented, initialize xim ... */
220   if ( xim_initted == False )
221     {
222       xim_initted = True;
223       XtGetApplicationNameAndClass (dpy, &name, &class);
224       DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
225
226       /* destroy callback for im */
227       ximcallback.callback = IMDestroyCallback;
228       ximcallback.client_data = (XPointer) d;
229       XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
230     }
231
232   /* activate XIC on all the X frames... */
233   DEVICE_FRAME_LOOP (tail, d)
234     {
235       struct frame *target_frame = XFRAME (XCAR (tail));
236       if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame))
237         {
238           XIM_init_frame (target_frame);
239         }
240     }
241   return;
242 }
243 #endif /* if THIS_IS_X11R6 */
244
245 /* Initialize XIM for X device.
246    Register the use of XIM using XRegisterIMInstantiateCallback. */
247 void
248 XIM_init_device (struct device *d)
249 {
250 #ifdef THIS_IS_X11R6
251   DEVICE_X_XIM (d) = NULL;
252   XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL,
253                                   IMInstantiateCallback,
254                                   /* The sixth parameter is of type
255                                      XPointer in XFree86 but (XPointer *)
256                                      on most other X11's. */
257                                   (void *) d);
258   return;
259 #else
260   Display *dpy = DEVICE_X_DISPLAY (d);
261   char *name, *class;
262   XIM xim;
263
264   XtGetApplicationNameAndClass (dpy, &name, &class);
265   DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
266   if (xim == NULL)
267     {
268       xim_warn ("XOpenIM() failed...no input server available\n");
269       return;
270     }
271   else
272     {
273       XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES (d), NULL);
274       return;
275     }
276 #endif
277 }
278
279
280 /*
281  * For the frames
282  */
283
284 /* Callback for the deleting frame. */
285 static void
286 XIM_delete_frame (Widget w, XtPointer client_data, XtPointer call_data)
287 {
288   struct frame *f = (struct frame *) client_data;
289   struct device *d = XDEVICE (FRAME_DEVICE (f));
290
291   if (DEVICE_X_XIM (d))
292     {
293       if (FRAME_X_XIC (f))
294         {
295           XDestroyIC (FRAME_X_XIC (f));
296           FRAME_X_XIC (f) = NULL;
297         }
298     }
299   return;
300 }
301
302 /* Initialize XIC for new frame.
303    Create an X input context (XIC) for this frame. */
304 void
305 XIM_init_frame (struct frame *f)
306 {
307   struct device *d = XDEVICE (FRAME_DEVICE (f));
308   XIM xim;
309   Widget w = FRAME_X_TEXT_WIDGET (f);
310   Window win = XtWindow (w);
311   XRectangle p_area = {0,0,1,1}, s_area = {0,0,1,1};
312   XPoint spot = {0,0};
313   XIMStyle style;
314   XVaNestedList p_list, s_list;
315   typedef struct
316   {
317     XIMStyles styles;
318     XFontSet  fontset;
319     Pixel     fg;
320     Pixel     bg;
321     char      *inputmethod;
322   } xic_vars_t;
323   xic_vars_t xic_vars;
324   XIC xic;
325
326 #define res(name, class, representation, field, default_value) \
327   { name, class, representation, sizeof(xic_vars.field), \
328      XtOffsetOf(xic_vars_t, field), XtRString, default_value }
329
330   static XtResource resources[] =
331   {
332     /*  name              class          represent'n   field    default value */
333     res(XtNximStyles,     XtCXimStyles,  XtRXimStyles, styles,  (XtPointer) DefaultXIMStyles),
334     res(XtNfontSet,       XtCFontSet,    XtRFontSet,   fontset, (XtPointer) XtDefaultFontSet),
335     res(XtNximForeground, XtCForeground, XtRPixel,     fg,      (XtPointer) XtDefaultForeground),
336     res(XtNximBackground, XtCBackground, XtRPixel,     bg,      (XtPointer) XtDefaultBackground)
337   };
338
339
340   xim = DEVICE_X_XIM (d);
341
342   if (!xim)
343     {
344       return;
345     }
346
347   w = FRAME_X_TEXT_WIDGET (f);
348
349   /*
350    * initialize XIC
351    */
352   if (FRAME_X_XIC (f)) return;
353   XtGetApplicationResources (w, &xic_vars,
354                              resources, XtNumber (resources),
355                              NULL, 0);
356   if (!xic_vars.fontset)
357     {
358       xim_warn ("Can't get fontset resource for Input Method\n");
359       FRAME_X_XIC (f) = NULL;
360       return;
361     }
362
363   /* construct xic */
364   XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES(d), NULL);
365   FRAME_X_XIC_STYLE (f) = style =
366     best_style (&xic_vars.styles, (XIMStyles *)DEVICE_X_XIM_STYLES(d));
367
368   p_list = XVaCreateNestedList (0,
369                                 XNArea,         &p_area,
370                                 XNSpotLocation, &spot,
371                                 XNForeground,   xic_vars.fg,
372                                 XNBackground,   xic_vars.bg,
373                                 XNFontSet,      xic_vars.fontset,
374                                 NULL);
375
376   s_list = XVaCreateNestedList (0,
377                                 XNArea,         &s_area,
378                                 XNForeground,   xic_vars.fg,
379                                 XNBackground,   xic_vars.bg,
380                                 XNFontSet,      xic_vars.fontset,
381                                 NULL);
382
383   FRAME_X_XIC (f) = xic =
384     XCreateIC (xim,
385                XNInputStyle, style,
386                XNClientWindow, win,
387                XNFocusWindow, win,
388                XNPreeditAttributes, p_list,
389                XNStatusAttributes, s_list,
390                NULL);
391   XFree (p_list);
392   XFree (s_list);
393
394   if (!xic)
395     {
396       xim_warn ("Warning: XCreateIC failed.\n");
397       return;
398     }
399
400   if (style & XIMPreeditPosition)
401     {
402       XPoint *frame_spot = &(FRAME_X_XIC_SPOT(f));
403       frame_spot->x = frame_spot->y = -1;
404     }
405
406   XIM_SetGeometry (f);
407
408   XSetICFocus (xic);
409
410 #ifdef THIS_IS_X11R6
411   /* when frame is going to be destroyed (closed) */
412   XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback,
413                  XIM_delete_frame, (XtPointer)f);
414 #endif
415 }
416
417
418 void
419 XIM_SetGeometry (struct frame *f)
420 {
421   XIC      xic   = FRAME_X_XIC (f);
422   XIMStyle style = FRAME_X_XIC_STYLE (f);
423   XRectangle area;
424
425   if (!xic || !f)
426     return;
427
428   if (style & XIMStatusArea)
429     {
430       /* Place Status Area in bottom right corner */
431       /* Negotiate geometry of status area */
432       /* See O'Reilly Xlib XIM chapter (but beware, it's buggy) */
433       XRectangle *needed;
434
435       /* If input method has existing status area, use its current size */
436       /* The following at least works for Sun's htt */
437       area.x = area.y = area.width = area.height = 0;
438       XIC_Value (Set, xic, XNStatusAttributes, XNAreaNeeded, &area);
439       XIC_Value (Get, xic, XNStatusAttributes, XNAreaNeeded, &needed);
440       if (needed->width == 0)   /* Use XNArea instead of XNAreaNeeded */
441         XIC_Value (Get, xic, XNStatusAttributes, XNArea, &needed);
442
443       area.width  = needed->width;
444       area.height = needed->height;
445       area.x = FRAME_RIGHT_BORDER_START  (f) - area.width;
446       area.y = FRAME_BOTTOM_BORDER_START (f) - area.height;
447
448 #ifdef DEBUG_XIM
449       stderr_out ("Putting StatusArea in x=%d y=%d w=%d h=%d\n",
450                   area.x, area.y, area.width, area.height);
451 #endif /* DEBUG_XIM */
452
453       XIC_Value (Set, xic, XNStatusAttributes, XNArea, &area);
454     }
455
456   if (style & XIMPreeditPosition)
457     {
458       /* Set Preedit Area to whole frame size (sans border) */
459       /* We include the border because Preedit window might be larger
460          than display line at edge. #### FIX: we should adjust to make
461          sure that there is always room for the spot sub-window */
462       area.x      = FRAME_LEFT_BORDER_START (f);
463       area.y      = FRAME_TOP_BORDER_START  (f);
464       area.width  = FRAME_RIGHT_BORDER_END  (f) - area.x;
465       area.height = FRAME_BOTTOM_BORDER_END (f) - area.y;
466       XIC_Value(Set, xic, XNPreeditAttributes, XNArea, &area);
467     }
468
469 #ifdef DEBUG_XIM
470   describe_XIC (xic);
471 #endif
472 }
473
474 void
475 XIM_SetSpotLocation (struct frame *f, int x, int y)
476 {
477   XIC xic = FRAME_X_XIC (f);
478   XPoint *spot = &(FRAME_X_XIC_SPOT (f));
479
480   /* Only care if we have a valid XIC using Over the Spot in
481    * a different location */
482   if (!xic ||
483       !(FRAME_X_XIC_STYLE (f) & XIMPreeditPosition) ||
484       (spot->x == (short) x &&
485        spot->y == (short) y))
486     return;
487
488   spot->x = (short) x;
489   spot->y = (short) y;
490
491   /* #### FIX: Must make sure spot fits within Preedit Area */
492   XIC_Value (Set, xic, XNPreeditAttributes, XNSpotLocation, spot);
493 #ifdef DEBUG_XIM
494   stderr_out ("Spot: %d %d\n", spot->x, spot->y);
495 #endif
496 }
497
498 void
499 XIM_focus_event (struct frame *f, int in_p)
500 {
501   if (FRAME_X_XIC (f) /* && FRAME_X_XIM_REGISTERED(f) */)
502     (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f));
503 }
504
505 #if 0
506 #define XIM_Composed_Text_BUFSIZE 64
507 typedef struct XIM_Composed_Text
508 {
509   int size;
510   wchar_t data [XIM_Composed_Text_BUFSIZE];
511 } XIM_Composed_Text;
512
513 static XIM_Composed_Text composed_input_buf = {XIM_Composed_Text_BUFSIZE, {0}};
514 Window main_window;
515
516 /* get_XIM_input -- Process results of input method composition.
517
518    This function copies the results of the input method composition to
519    composed_input_buf.  Then for each character, a custom event of type
520    wc_atom is sent with the character as its data.
521
522    It is probably more efficient to copy the composition results to some
523    allocated memory and send a single event pointing to that memory.
524    That would cut down on the event processing as well as allow quick
525    insertion into the buffer of the whole string.  It might require some
526    care, though, to avoid fragmenting memory through the allocation and
527    freeing of many small chunks.  Maybe the existing system for
528    (single-byte) string allocation can be used, multiplying the length by
529    sizeof (wchar_t) to get the right size.
530 */
531 void
532 get_XIM_input (XKeyPressedEvent *x_key_event, XIC ic, Display *dpy)
533 {
534   KeySym keysym;
535   Status status;
536   int len;
537   int i;
538   XClientMessageEvent new_event;
539
540 retry:
541   len = XwcLookupString (ic, x_key_event, composed_input_buf.data,
542                          composed_input_buf.size, &keysym, &status);
543   switch (status)
544     {
545     case XBufferOverflow:
546       /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
547       goto retry;
548     case XLookupChars:
549       break;
550     default:
551       abort ();
552     }
553
554   new_event.type = ClientMessage;
555   new_event.display = x_key_event->display;
556   new_event.window = x_key_event->window;
557   new_event.message_type = wc_atom;
558   new_event.format = 32;  /* 32-bit wide data */
559   new_event.data.l[2] = new_event.data.l[3] = new_event.data.l[4] = 0L;
560   new_event.data.l[0] = x_key_event->time;
561   for (i = 0; i < len; i++)
562     {
563       new_event.data.l[1] = ((wchar_t *) composed_input_buf.data)[i];
564       XSendEvent (display, main_window, False, 0L, (XEvent *) &new_event);
565     }
566 }
567 #endif /* 0 */
568
569 /* ============================================================== */
570 /* X input method style determination */
571 /* ============================================================== */
572
573 #if 0
574 #define done(type, value)                \
575   if (toVal->addr != NULL) {             \
576     if (toVal->size < sizeof(type)) {    \
577       toVal->size = sizeof(type);        \
578       return False;                      \
579     }                                    \
580     *(type*)toVal->addr = (value);       \
581   } else {                               \
582     static type static_val;              \
583     static_val = (value);                \
584     toVal->addr = (XPointer)&static_val; \
585   }                                      \
586   toVal->size = sizeof(type);            \
587   return True /* Caller supplies `;' */
588 #endif /* 0 */
589
590 /*
591  * This is a standard Xt type converter, except that the caller MUST
592  * supply a proper non-NULL toVal XIMStyles structure that we will
593  * fill in.
594  *
595  * fromVal points to a string like
596  *
597  "XIMPreeditPosition|XIMStatusArea,
598  XIMPreeditPosition|XIMStatusNothing
599  XIMPreeditNothing|XIMStatusNothing"
600  *
601  * This is converted in the obvious way to a XIMStyles structure.
602  *
603  * mrb: #### Fix this to handle Motif-style specifications for
604  * XIMStyles as well: overTheSpot, rootWindow, none */
605
606 /* XtTypeConverter */
607 Boolean
608 EmacsXtCvtStringToXIMStyles (
609   Display     *dpy,
610   XrmValuePtr  args,
611   Cardinal    *num_args,
612   XrmValuePtr  fromVal,
613   XrmValuePtr  toVal,
614   XtPointer   *converter_data)
615 {
616 #define STYLE_INFO(style) { style, #style, sizeof(#style) }
617   static struct XIMStyleInfo
618   {
619     const XIMStyle style;
620     const char   * const name;
621     const int      namelen;
622   } emacs_XIMStyleInfo[] = {
623     STYLE_INFO (XIMPreeditPosition|XIMStatusArea),
624     STYLE_INFO (XIMPreeditPosition|XIMStatusNothing),
625     STYLE_INFO (XIMPreeditPosition|XIMStatusNone),
626     STYLE_INFO (XIMPreeditNothing|XIMStatusArea),
627     STYLE_INFO (XIMPreeditNothing|XIMStatusNothing),
628     STYLE_INFO (XIMPreeditNothing|XIMStatusNone),
629     STYLE_INFO (XIMPreeditNone|XIMStatusArea),
630     STYLE_INFO (XIMPreeditNone|XIMStatusNothing),
631     STYLE_INFO (XIMPreeditNone|XIMStatusNone)
632   };
633 #undef STYLE_INFO
634
635   char *s   = (char *) fromVal->addr;
636   char *end = s + fromVal->size;
637   XIMStyles * const p = (XIMStyles *) toVal->addr;
638   const char * const delimiter = " \t\n\r:;," ;
639   const int  max_styles = XtNumber(emacs_XIMStyleInfo);
640   int i;
641   char *c;
642
643 #ifdef DEBUG_XIM
644   stderr_out ("EmacsCvtStringToXIMStyles called with size=%d, string=\"%s\"\n",
645               fromVal->size, (char *) fromVal->addr);
646 #endif /* DEBUG_XIM */
647
648   if (*num_args != 0)
649     {
650       XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
651       XtAppWarningMsg(the_app_con, "wrongParameters", "cvtStringToXIMStyle",
652                       "XtToolkitError",
653                       "String to XIMStyle conversion requires exactly 0 parameters",
654                       (String *)NULL, (Cardinal *)NULL);
655       return False;
656     }
657
658 #ifdef DEBUG_XEMACS
659   /* Make sure caller is giving us good data */
660   assert (fromVal->addr != NULL);
661   assert (fromVal->size == strlen(fromVal->addr)+1);
662   assert (toVal->addr   != NULL);
663   assert (toVal->size   == sizeof(XIMStyles));
664 #endif /* DEBUG_XEMACS */
665
666   p->count_styles = 0;
667   p->supported_styles = xnew_array (XIMStyle, max_styles);
668
669   /*
670    * The following routine assumes that the style name resource is
671    * identical with the programmatic name of style.  For example,
672    * "XIMPreeditPosition|XIMStatusArea" means the
673    * XIMPreeditPosition|XIMStatusArea value is specified.  If the
674    * style name is changed, such as "OverTheSpot|imDisplaysInClient",
675    * the parsing logic below should be modified as well. */
676
677   if ((c = strtok(s, delimiter)) == NULL)
678     c = end;
679
680   while (c < end)
681     {
682       for(i=0 ; i<max_styles ; i++)
683         {
684           struct XIMStyleInfo *rec = emacs_XIMStyleInfo + i;
685           if(!strncmp(c, rec->name, rec->namelen - 1)) {
686             p->supported_styles[p->count_styles] = rec->style;
687             p->count_styles++;
688             break;
689           }
690         }
691       if((c = strtok(NULL, delimiter)) == NULL) {
692         break ;
693       }
694     }
695
696   if (p->count_styles == 0)
697     {   /* No valid styles? */
698       char *buf = (char *)alloca (strlen (fromVal->addr)
699                                   + strlen (DefaultXIMStyles)
700                                   + 100);
701       XrmValue new_from;
702       XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
703
704       sprintf(buf, "Cannot convert string \"%s\" to type XIMStyles.\n"
705               "Using default string \"%s\" instead.\n",
706               fromVal->addr, DefaultXIMStyles);
707       XtAppWarningMsg(the_app_con, "wrongParameters", "cvtStringToXIMStyle",
708                       "XtToolkitError",
709                       buf, (String *)NULL, (Cardinal *)NULL);
710       new_from.addr = DefaultXIMStyles;
711       new_from.size = sizeof(DefaultXIMStyles);
712       return EmacsXtCvtStringToXIMStyles (dpy, args, num_args,
713                                           &new_from, toVal, converter_data);
714     }
715   XREALLOC_ARRAY (p->supported_styles, XIMStyle, p->count_styles);
716   *converter_data = (char *) True;
717   return True;
718 }
719
720 /* XtDestructor */
721 void
722 EmacsFreeXIMStyles (
723   XtAppContext app,
724   XrmValuePtr  toVal,
725   XtPointer    converter_data,
726   XrmValuePtr  args,
727   Cardinal    *num_args)
728 {
729 #ifdef DEBUG_XIM
730   stderr_out ("Converter data: %x\n", converter_data);
731   stderr_out ("EmacsFreeXIMStyles called\n");
732 #endif /* DEBUG_XIM */
733
734   if (*num_args != 0)
735     {
736       XtAppWarningMsg(app, "wrongParameters","freeXIMStyles","XtToolkitError",
737                       "Freeing an XIMStyles requires that zero arguments be passwd",
738                       (String *)NULL, (Cardinal *)NULL);
739       return;
740     }
741
742   if (converter_data)
743     {
744       Boolean free_p    = (Boolean) (int) converter_data;
745       XIMStyles *styles = (XIMStyles *) toVal->addr;
746       if (free_p)
747         XFree ( styles->supported_styles );
748     }
749 }
750
751 #if 0
752 /* O'Reilly XLib Programming Manual, pg. 371 */
753 /* Much nicer implementation than O'Reilly */
754 /* Choose the more `complicated', hence nicer, XIM input style */
755 static XIMStyle
756 BetterStyle (XIMStyle s, XIMStyle t)
757 {
758 #define CHECK_XIMStyle_BIT(bit)  \
759   if ((s ^ t) & bit) { return (s & bit) ? s : t; }
760
761   CHECK_XIMStyle_BIT (XIMPreeditCallbacks);
762   CHECK_XIMStyle_BIT (XIMPreeditPosition);
763   CHECK_XIMStyle_BIT (XIMPreeditArea);
764   CHECK_XIMStyle_BIT (XIMPreeditNothing);
765   CHECK_XIMStyle_BIT (XIMStatusCallbacks);
766   CHECK_XIMStyle_BIT (XIMStatusArea);
767   CHECK_XIMStyle_BIT (XIMStatusNothing);
768 #undef CHECK_XIMStyle_BIT
769   return s ? s : t ;
770 }
771 #endif /* 0 */
772
773 /* Choose the best style, given:
774  * - user preferences (already checked to be supported by XEmacs)
775  * - styles supported by the input method */
776 #define DEFAULTStyle  (XIMPreeditNothing|XIMStatusNothing)
777 static XIMStyle
778 best_style (XIMStyles *user, XIMStyles *xim)
779 {
780   REGISTER int i, j;
781   for (i=0 ; i<user->count_styles ; i++)
782     {
783       for (j=0 ; j<xim->count_styles ; j++)
784         {
785           if (user->supported_styles[i] == xim->supported_styles[j])
786             return user->supported_styles[i];
787         }
788     }
789   return DEFAULTStyle; /* Default Style */
790 }
791
792 /* These lisp-callable functions will be sealed until xim-leim is needed. 
793    Oct 22 1999 - kazz */
794 #if 0
795 /*
796  * External callable function for XIM
797  */
798 DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /*
799 Open the XIC on the frame if XIM is available.
800 Commonly, use this as \(x-open-xim \(selected-frame)).
801 If the frame is not on X device, return signal.
802 If XIC is created successfully return t.  If not return nil.
803 */
804        (frame))
805 {
806   struct frame *f;
807
808   CHECK_LIVE_FRAME (frame);
809   f = XFRAME (frame);
810   if (!FRAME_X_P (f))
811     return signal_simple_error ("This frame is not on X device", frame);
812
813   XIM_init_frame (f);
814   return FRAME_X_XIC (f) ? Qt : Qnil;
815 }
816
817 DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /*
818 Close the XIC on the frame if it exists.
819 Commonly, use this as \(x-close-xim \(selected-frame)).
820 If the frame is not on X device, return signal.
821 Otherwise, it destroys the XIC if it exists, then returns t anyway.
822 */
823        (frame))
824 {
825   struct frame *f;
826   struct device *d;
827
828   CHECK_LIVE_FRAME (frame);
829   f = XFRAME (frame);
830   if (!FRAME_X_P (f))
831     return signal_simple_error ("This frame is not on X device", frame);
832
833   d = XDEVICE (FRAME_DEVICE (f));
834   if (DEVICE_X_XIM (d)) {
835     /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */
836     FRAME_X_XIC (XFRAME (f)) = NULL;
837   }
838   return Qt;
839 }
840 #endif /* if 0 */
841
842 void
843 syms_of_input_method_xlib (void)
844 {
845   defsymbol (&Qxim_xlib, "xim-xlib");
846 #if 0 /* see above */
847   DEFSUBR (Fx_open_xim);
848   DEFSUBR (Fx_close_xim);
849 #endif
850 }
851
852 void
853 vars_of_input_method_xlib (void)
854 {
855   Fprovide (intern ("xim"));
856 }
857
858
859 /* ====================================================================== */
860 /* Internal Debugging Routines */
861 /* ====================================================================== */
862 #ifdef DEBUG_XEMACS
863
864 void
865 describe_XIM (XIM xim)
866 {
867   XIMStyles *styles;
868
869   /* Print locale of XIM */
870   stderr_out ("\nXIM Locale of IM: %s\n", XLocaleOfIM(xim));
871
872   /* List supported input method styles */
873   XGetIMValues(xim, XNQueryInputStyle, &styles, NULL);
874
875   stderr_out ("\n%d input style(s) supported by input method.\n",
876               styles->count_styles);
877
878 #ifdef DEBUG_XIM
879   {
880     int i;
881     for (i=0; i < styles->count_styles; i++)
882       describe_XIMStyle (styles->supported_styles[i]);
883   }
884 #endif /* DEBUG_XIM */
885   XFree(styles);
886 }
887
888 void
889 describe_XFontSet (XFontSet fontset)
890 {
891   XFontStruct **font_struct_list;
892   char **font_name_list;
893   int count, i;
894
895   if (fontset == NULL)
896     {
897       stderr_out ("NULL\n");
898       return;
899     }
900
901   count = XFontsOfFontSet (fontset, &font_struct_list, &font_name_list);
902   stderr_out ( "%d font(s) available:\n", count);
903   for (i=0 ; i < count ; i++)
904     stderr_out ("Font: %s\n", *(font_name_list+i));
905 }
906
907 void
908 describe_Status (Status status)
909 {
910 #define DESCRIBE_STATUS(value) \
911   if (status == value) stderr_out ("Status: " #value "\n")
912
913   DESCRIBE_STATUS (XBufferOverflow);
914   DESCRIBE_STATUS (XLookupNone);
915   DESCRIBE_STATUS (XLookupKeySym);
916   DESCRIBE_STATUS (XLookupBoth);
917   DESCRIBE_STATUS (XLookupChars);
918 #undef DESCRIBE_STATUS
919 }
920
921 void
922 describe_Window (Window win)
923 {
924   char xwincmd[128];
925   sprintf (xwincmd, "xwininfo -id 0x%x >&2; xwininfo -events -id 0x%x >&2",
926            (int) win, (int) win);
927   system (xwincmd);
928 }
929
930 void
931 describe_XIC (XIC xic)
932 {
933   XIMStyle style;
934   Window client_win=0, focus_win=0;
935   char *resourceName  = NULL;
936   char *resourceClass = NULL;
937   char *bad_arg       = NULL;
938   unsigned long filter_mask = NoEventMask;
939   XVaNestedList p_list, s_list;
940   XFontSet      p_fontset = NULL, s_fontset = NULL;
941   Pixel         p_fg=0, p_bg = 0, s_fg=0, s_bg = 0;
942   XRectangle   *p_area   = NULL, *s_area   = NULL;
943   XRectangle   *p_needed = NULL, *s_needed = NULL;
944   XPoint       *p_spot = NULL;
945
946   /* Check for valid input context and method */
947   if (!xic)
948     stderr_out ("Input method is NULL\n");
949
950   if (!XIMOfIC(xic))
951     stderr_out ("XIMOfIC() returns NULL\n");
952
953   /* Print out Input Context Attributes */
954   p_list = XVaCreateNestedList (0,
955                                 XNFontSet,      &p_fontset,
956                                 XNArea,         &p_area,
957                                 XNAreaNeeded,   &p_needed,
958                                 XNSpotLocation, &p_spot,
959                                 XNForeground,   &p_fg,
960                                 XNBackground,   &p_bg,
961                                 NULL);
962
963   s_list = XVaCreateNestedList (0,
964                                 XNFontSet,      &s_fontset,
965                                 XNArea,         &s_area,
966                                 XNAreaNeeded,   &s_needed,
967                                 XNForeground,   &s_fg,
968                                 XNBackground,   &s_bg,
969                                 NULL);
970
971   bad_arg = XGetICValues(xic,
972                          XNInputStyle,        &style,
973                          XNFilterEvents,      &filter_mask,
974                          XNClientWindow,      &client_win,
975                          XNFocusWindow,       &focus_win,
976                          XNResourceName,      &resourceName,
977                          XNResourceClass,     &resourceClass,
978                          XNPreeditAttributes, p_list,
979                          XNStatusAttributes,  s_list,
980                          NULL);
981   XFree(p_list);
982   XFree(s_list);
983
984   if (bad_arg != NULL)
985     stderr_out ("Couldn't get IC value: %s\n", bad_arg);
986
987   stderr_out ("\nInput method context attributes:\n");
988   stderr_out ("Style: "); describe_XIMStyle (style);
989   stderr_out ("Client window: %lx\n", (unsigned long int)client_win);
990   stderr_out ("Focus window: %lx\n",  (unsigned long int)focus_win);
991   stderr_out ("Preedit:\n");
992   describe_XRectangle ("  Area", p_area);
993   describe_XRectangle ("  Area needed", p_needed);
994   stderr_out ("  foreground: %lx\n", (unsigned long int)p_fg);
995   stderr_out ("  background: %lx\n", (unsigned long int)p_bg);
996   stderr_out ("  fontset: "); describe_XFontSet (p_fontset);
997   stderr_out ("Status:\n");
998   describe_XRectangle ("  Area", s_area);
999   describe_XRectangle ("  Area needed", s_needed);
1000   stderr_out ("  foreground: %lx\n", (unsigned long int)s_fg);
1001   stderr_out ("  background: %lx\n", (unsigned long int)s_bg);
1002   stderr_out ("  fontset: \n"); describe_XFontSet (s_fontset);
1003   stderr_out ("XNResourceName: %s\n",  resourceName  ? resourceName  : "NULL");
1004   stderr_out ("XNResourceClass: %s\n", resourceClass ? resourceClass : "NULL");
1005   stderr_out ("XNFilterEvents: "); describe_event_mask (filter_mask);
1006 }
1007
1008 void
1009 describe_XRectangle (char *name, XRectangle *r)
1010 {
1011   if (r == NULL)
1012     stderr_out ("%s: NULL\n", name);
1013   else
1014     stderr_out ("%s: x=%d y=%d w=%d h=%d\n",
1015                 name, r->x, r->y, r->width, r->height);
1016 }
1017
1018 /* Print out elements of Event mask */
1019 /* Defines from X11/X.h */
1020 void
1021 describe_event_mask (unsigned long mask)
1022 {
1023 #define DESCRIBE_EVENT_MASK(bit) if ((bit) & mask) stderr_out (#bit " ")
1024   DESCRIBE_EVENT_MASK (NoEventMask);
1025   DESCRIBE_EVENT_MASK (KeyPressMask);
1026   DESCRIBE_EVENT_MASK (KeyReleaseMask);
1027   DESCRIBE_EVENT_MASK (ButtonPressMask);
1028   DESCRIBE_EVENT_MASK (ButtonReleaseMask);
1029   DESCRIBE_EVENT_MASK (EnterWindowMask);
1030   DESCRIBE_EVENT_MASK (LeaveWindowMask);
1031   DESCRIBE_EVENT_MASK (PointerMotionMask);
1032   DESCRIBE_EVENT_MASK (PointerMotionHintMask);
1033   DESCRIBE_EVENT_MASK (Button1MotionMask);
1034   DESCRIBE_EVENT_MASK (Button2MotionMask);
1035   DESCRIBE_EVENT_MASK (Button3MotionMask);
1036   DESCRIBE_EVENT_MASK (Button4MotionMask);
1037   DESCRIBE_EVENT_MASK (Button5MotionMask);
1038   DESCRIBE_EVENT_MASK (ButtonMotionMask);
1039   DESCRIBE_EVENT_MASK (KeymapStateMask);
1040   DESCRIBE_EVENT_MASK (ExposureMask);
1041   DESCRIBE_EVENT_MASK (VisibilityChangeMask);
1042   DESCRIBE_EVENT_MASK (StructureNotifyMask);
1043   DESCRIBE_EVENT_MASK (ResizeRedirectMask);
1044   DESCRIBE_EVENT_MASK (SubstructureNotifyMask);
1045   DESCRIBE_EVENT_MASK (SubstructureRedirectMask);
1046   DESCRIBE_EVENT_MASK (FocusChangeMask);
1047   DESCRIBE_EVENT_MASK (PropertyChangeMask);
1048   DESCRIBE_EVENT_MASK (ColormapChangeMask);
1049   DESCRIBE_EVENT_MASK (OwnerGrabButtonMask);
1050 #undef DESCRIBE_EVENT_MASK
1051   stderr_out("\n");
1052 }
1053
1054 void
1055 describe_XIMStyle (XIMStyle style)
1056 {
1057 #define DESCRIBE_STYLE(bit) \
1058   if (bit & style)          \
1059     stderr_out (#bit " ");
1060
1061   DESCRIBE_STYLE (XIMPreeditArea);
1062   DESCRIBE_STYLE (XIMPreeditCallbacks);
1063   DESCRIBE_STYLE (XIMPreeditPosition);
1064   DESCRIBE_STYLE (XIMPreeditNothing);
1065   DESCRIBE_STYLE (XIMPreeditNone);
1066   DESCRIBE_STYLE (XIMStatusArea);
1067   DESCRIBE_STYLE (XIMStatusCallbacks);
1068   DESCRIBE_STYLE (XIMStatusNothing);
1069   DESCRIBE_STYLE (XIMStatusNone);
1070 #undef DESCRIBE_STYLE
1071   stderr_out("\n");
1072 }
1073
1074 void
1075 describe_XIMStyles (XIMStyles *p)
1076 {
1077   int i;
1078   stderr_out ("%d Style(s):\n", p->count_styles);
1079   for (i=0; i<p->count_styles ; i++)
1080     {
1081       describe_XIMStyle (p->supported_styles[i]);
1082     }
1083 }
1084
1085 #endif /* DEBUG_XEMACS */
1086
1087 /* Random cruft follows */
1088
1089 #if 0
1090 static void
1091 Unit_Test (struct frame *f, char * s)
1092 /* mrb unit testing */
1093 {
1094   XrmValue fromVal, toVal;
1095
1096   fromVal.addr = s;
1097   fromVal.size = strlen (s);
1098   toVal.addr = (XtPointer) &user_preferred_XIMStyles;
1099   toVal.size = sizeof (XIMStyles);
1100
1101   if (XtConvertAndStore (FRAME_X_TEXT_WIDGET (f), XtRString, &fromVal,
1102                          XtRXimStyles, &toVal) != False)
1103     {
1104       stderr_out ("Unit_Test: fromVal.addr=0x%x\n",fromVal.addr);
1105       stderr_out ("Unit_Test: fromVal.size=%d\n",  fromVal.size);
1106       stderr_out ("Unit_Test:   toVal.addr=0x%x\n",  toVal.addr);
1107       stderr_out ("Unit_Test:   toVal.size=%d\n",    toVal.size);
1108       describe_XIMStyles ((XIMStyles *) toVal.addr);
1109     }
1110 }
1111 #endif
1112
1113 #if 0
1114 /* Get a fontset for IM to use */
1115 void
1116 x_init_fontset (struct device *d)
1117 {
1118   Display *dpy = DEVICE_X_DISPLAY (d);
1119   XFontSet fontset;
1120   char ** missing_charsets;
1121   int num_missing_charsets;
1122   char * default_string;
1123   /*  char * font_set_string = "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*";*/
1124   char * font_set_string = "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*, -misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0,-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0, -misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0" ;
1125
1126   DEVICE_X_FONTSET (d) = fontset =
1127     XCreateFontSet (dpy,
1128                     font_set_string,
1129                     &missing_charsets,
1130                     &num_missing_charsets,
1131                     &default_string);
1132
1133   if (fontset == NULL)
1134     {
1135       stderr_out ("Unable to create fontset from string:\n%s\n", font_set_string);
1136       return;
1137     }
1138   if (num_missing_charsets > 0)
1139     {
1140       int i;
1141       stderr_out ("\nMissing charsets for fontset %s:\n", font_set_string);
1142       for (i=0; i < num_missing_charsets; i++)
1143         {
1144           stderr_out ("%s\n", missing_charsets[i]);
1145         }
1146       XFreeStringList (missing_charsets);
1147       stderr_out ("Default string: %s\n", default_string);
1148     }
1149
1150 #ifdef DEBUG_XIM
1151   describe_XFontSet (fontset);
1152 #endif
1153 }
1154 #endif /* 0 */