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