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