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