comparison src/input-method-xlib.c @ 359:8e84bee8ddd0 r21-1-9

Import from CVS: tag r21-1-9
author cvs
date Mon, 13 Aug 2007 10:57:55 +0200
parents 19dcec799385
children cc15677e0335
comparison
equal deleted inserted replaced
358:fed6e0f6a03a 359:8e84bee8ddd0
24 24
25 /* This file implements an interface to X input methods, available 25 /* This file implements an interface to X input methods, available
26 with X11R5 and above. See O'Reilly, Xlib programmer's guide, 26 with X11R5 and above. See O'Reilly, Xlib programmer's guide,
27 and X11 R6 release guide chapters on internationalized input, 27 and X11 R6 release guide chapters on internationalized input,
28 for further details */ 28 for further details */
29
30 /*
31 Policy:
32
33 The XIM is of the device, by the device, for the device.
34 The XIC is of each frame, by each frame, for each frame.
35 The exceptions are:
36 1. Activate XICs on poor frames when the XIM is back.
37 2. Deactivate all the XICs when the XIM go down.
38
39 Methods:
40
41 - Register a callback for an XIM when the X device is being initialized.
42 XIM_init_device (d) { XRegisterIMInstantiateCallback (); }
43 The "XRegisterIMInstantiateCallback" is called when an XIM become
44 available on the X display.
45
46 - Catch the XIC when the frame is being initialized if XIM was available.
47 XIM_init_frame (f) { ... XCreateIC (); ... }
48
49 - Release the XIC when the frame is being closed.
50 XIM_delete_frame (f) { ... FRAME_X_XIC (f) = NULL; ... }
51 "XIM_delete_frame" is a "DestroyCallback" function declared in
52 XIM_init_frame ();
53
54 - Release all the XICs when the XIM was down accidentally.
55 In IMDestroyCallback:
56 DEVICE_FRAME_LOOP (...) { FRAME_X_XIC (f) = NULL; }
57
58 - Re-enable XIC for all the frames which doesn't have XIC when the XIM
59 is back.
60 In IMInstantiateCallback:
61 DEVICE_FRAME_LOOP (...) { XIM_init_frame (f); }
62
63
64 Note:
65
66 - Currently, we don't use XDestroyIC because of _XimProtoCloseIM
67 (internally registered as im->methods->close) does "Xfree (ic)".
68
69 */
29 70
30 #include <config.h> 71 #include <config.h>
31 #include "lisp.h" 72 #include "lisp.h"
32 #include <X11/Xlocale.h> /* More portable than <locale.h> ? */ 73 #include <X11/Xlocale.h> /* More portable than <locale.h> ? */
33 #include "frame.h" 74 #include "frame.h"
36 #include "buffer.h" 77 #include "buffer.h"
37 #include "console-x.h" 78 #include "console-x.h"
38 #include "EmacsFrame.h" 79 #include "EmacsFrame.h"
39 #include "events.h" 80 #include "events.h"
40 81
82 #ifdef THIS_IS_X11R6
83 #include <X11/IntrinsicP.h>
84 #include <X11/Xaw/XawImP.h>
85 #endif
86
41 #ifndef XIM_XLIB 87 #ifndef XIM_XLIB
42 #error XIM_XLIB is not defined?? 88 #error XIM_XLIB is not defined??
43 #endif 89 #endif
90
91 Lisp_Object Qxim_xlib;
92 #define xim_warn(str) warn_when_safe (Qxim_xlib, Qwarning, str);
93 #define xim_warn1(fmt, str) warn_when_safe (Qxim_xlib, Qwarning, fmt, str);
94 #define xim_info(str) warn_when_safe (Qxim_xlib, Qinfo, str);
44 95
45 /* Get/Set IC values for just one attribute */ 96 /* Get/Set IC values for just one attribute */
46 #ifdef DEBUG_XEMACS 97 #ifdef DEBUG_XEMACS
47 #define XIC_Value(Get_Set, xic, name, attr, value) \ 98 #define XIC_Value(Get_Set, xic, name, attr, value) \
48 do { \ 99 do { \
70 "XIMPreeditNothing|XIMStatusNone\n" 121 "XIMPreeditNothing|XIMStatusNone\n"
71 "XIMPreeditNone|XIMStatusArea\n" 122 "XIMPreeditNone|XIMStatusArea\n"
72 "XIMPreeditNone|XIMStatusNothing\n" 123 "XIMPreeditNone|XIMStatusNothing\n"
73 "XIMPreeditNone|XIMStatusNone"; 124 "XIMPreeditNone|XIMStatusNone";
74 125
126 static Boolean xim_initted = False;
127
75 static XIMStyle best_style (XIMStyles *user, XIMStyles *xim); 128 static XIMStyle best_style (XIMStyles *user, XIMStyles *xim);
76 129
77 void 130 void
78 Initialize_Locale (void) 131 Initialize_Locale (void)
79 { 132 {
85 at this point, we don't know yet whether we're gonna need an X11 frame, 138 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 */ 139 we should really do it manually and not use Xlib's dumb default routine */
87 /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/ 140 /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/
88 if ((locale = setlocale (LC_ALL, "")) == NULL) 141 if ((locale = setlocale (LC_ALL, "")) == NULL)
89 { 142 {
90 stderr_out ("Can't set locale.\n"); 143 xim_warn ("Can't set locale.\n"
91 stderr_out ("Using C locale instead.\n"); 144 "Using C locale instead.\n");
92 putenv ("LANG=C"); 145 putenv ("LANG=C");
93 putenv ("LC_ALL=C"); 146 putenv ("LC_ALL=C");
94 if ((locale = setlocale (LC_ALL, "C")) == NULL) 147 if ((locale = setlocale (LC_ALL, "C")) == NULL)
95 { 148 {
96 stderr_out ("Can't even set locale to `C'!\n"); 149 xim_warn ("Can't even set locale to `C'!\n");
97 return; 150 return;
98 } 151 }
99 } 152 }
100 153
101 if (!XSupportsLocale ()) 154 if (!XSupportsLocale ())
102 { 155 {
103 stderr_out ("X Windows does not support locale `%s'\n", locale); 156 xim_warn1 ("X Windows does not support locale `%s'\n"
104 stderr_out ("Using C Locale instead\n"); 157 "Using C Locale instead\n", locale);
105 putenv ("LANG=C"); 158 putenv ("LANG=C");
106 putenv ("LC_ALL=C"); 159 putenv ("LC_ALL=C");
107 if ((locale = setlocale (LC_ALL, "C")) == NULL) 160 if ((locale = setlocale (LC_ALL, "C")) == NULL)
108 { 161 {
109 stderr_out ("Can't even set locale to `C'!\n"); 162 xim_warn ("Can't even set locale to `C'!\n");
110 return; 163 return;
111 } 164 }
112 if (!XSupportsLocale ()) 165 if (!XSupportsLocale ())
113 { 166 {
114 stderr_out ("X Windows does not even support locale `C'!\n"); 167 xim_warn ("X Windows does not even support locale `C'!\n");
115 return; 168 return;
116 } 169 }
117 } 170 }
118 171
119 setlocale(LC_NUMERIC, "C"); 172 setlocale(LC_NUMERIC, "C");
120 173
121 if (XSetLocaleModifiers ("") == NULL) 174 if (XSetLocaleModifiers ("") == NULL)
122 { 175 {
123 stderr_out ("XSetLocaleModifiers(\"\") failed\n"); 176 xim_warn ("XSetLocaleModifiers(\"\") failed\n"
124 stderr_out ("Check the value of the XMODIFIERS environment variable.\n"); 177 "Check the value of the XMODIFIERS environment variable.\n");
125 } 178 }
126 } 179 }
127 180
128 /* Create X input method for device */ 181 #ifdef THIS_IS_X11R6 /* Callbacks for IM are supported from X11R6 or later. */
182 /* Called from when XIM is destroying.
183 Clear all the XIC when the XIM was destroying... */
184 static void
185 IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data)
186 {
187 struct device *d = (struct device *)client_data;
188 Lisp_Object tail;
189
190 DEVICE_FRAME_LOOP (tail, d)
191 {
192 struct frame *target_frame = XFRAME (XCAR (tail));
193 if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame))
194 {
195 /* XDestroyIC (FRAME_X_XIC (target_frame)); */
196 FRAME_X_XIC (target_frame) = NULL;
197 }
198 }
199
200 DEVICE_X_XIM (d) = NULL;
201 xim_initted = False;
202 return;
203 }
204
205 /* This is registered in XIM_init_device (when DEVICE is initializing).
206 This activates XIM when XIM becomes available. */
207 static void
208 IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
209 {
210 struct device *d = (struct device *)client_data;
211 XIM xim;
212 char *name, *class;
213 XIMCallback ximcallback;
214 Lisp_Object tail;
215
216 /* if no xim is presented, initialize xim ... */
217 if ( xim_initted == False )
218 {
219 xim_initted = True;
220 XtGetApplicationNameAndClass (dpy, &name, &class);
221 DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
222
223 /* destroy callback for im */
224 ximcallback.callback = IMDestroyCallback;
225 ximcallback.client_data = (XPointer) d;
226 XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
227 }
228
229 /* activate XIC on all the X frames... */
230 DEVICE_FRAME_LOOP (tail, d)
231 {
232 struct frame *target_frame = XFRAME (XCAR (tail));
233 if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame))
234 {
235 XIM_init_frame (target_frame);
236 }
237 }
238 return;
239 }
240 #endif /* if THIS_IS_X11R6 */
241
242 /* Initialize XIM for X device.
243 Register the use of XIM using XRegisterIMInstantiateCallback. */
129 void 244 void
130 XIM_init_device (struct device *d) 245 XIM_init_device (struct device *d)
131 { 246 {
247 #ifdef THIS_IS_X11R6
248 DEVICE_X_XIM (d) = NULL;
249 XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL,
250 IMInstantiateCallback, (XPointer) d);
251 return;
252 #else
132 Display *dpy = DEVICE_X_DISPLAY (d); 253 Display *dpy = DEVICE_X_DISPLAY (d);
133 char *name, *class; 254 char *name, *class;
134 XIM xim; 255 XIM xim;
135 256
136 XtGetApplicationNameAndClass (dpy, &name, &class); 257 XtGetApplicationNameAndClass (dpy, &name, &class);
137
138 DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class); 258 DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
139
140 if (xim == NULL) 259 if (xim == NULL)
141 { 260 {
142 stderr_out ("Warning: XOpenIM() failed...no input server available\n"); 261 xim_warn ("XOpenIM() failed...no input server available\n");
143 return; 262 return;
144 } 263 }
145 else 264 else
146 { 265 {
147 /* Get supported styles */
148 XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES (d), NULL); 266 XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES (d), NULL);
149 #ifdef DEBUG_XIM 267 return;
150 describe_XIM (xim); 268 }
151 #endif 269 #endif
152 } 270 }
153 } 271
154 272
155 /* Create an X input context for this frame. */ 273 /*
274 * For the frames
275 */
276
277 /* Callback for the deleting frame. */
278 static void
279 XIM_delete_frame (Widget w, XtPointer client_data, XtPointer call_data)
280 {
281 struct frame *f = (struct frame *) client_data;
282 struct device *d = XDEVICE (FRAME_DEVICE (f));
283
284 if (DEVICE_X_XIM (d))
285 {
286 if (FRAME_X_XIC (f))
287 {
288 XDestroyIC (FRAME_X_XIC (f));
289 FRAME_X_XIC (f) = NULL;
290 }
291 }
292 return;
293 }
294
295 /* Initialize XIC for new frame.
296 Create an X input context (XIC) for this frame. */
156 void 297 void
157 XIM_init_frame (struct frame *f) 298 XIM_init_frame (struct frame *f)
158 { 299 {
159 struct device *d = XDEVICE (FRAME_DEVICE (f)); 300 struct device *d = XDEVICE (FRAME_DEVICE (f));
160 XIM xim = DEVICE_X_XIM (d); 301 XIM xim;
161 XIC xic;
162 Widget w = FRAME_X_TEXT_WIDGET (f); 302 Widget w = FRAME_X_TEXT_WIDGET (f);
163 Window win = XtWindow (w); 303 Window win = XtWindow (w);
164 XRectangle p_area = {0,0,1,1}, s_area={0,0,1,1}; 304 XRectangle p_area = {0,0,1,1}, s_area = {0,0,1,1};
165 XPoint spot = {0,0}; 305 XPoint spot = {0,0};
166 XIMStyle style; 306 XIMStyle style;
167 XVaNestedList p_list, s_list; 307 XVaNestedList p_list, s_list;
168
169 typedef struct 308 typedef struct
170 { 309 {
171 XIMStyles styles; 310 XIMStyles styles;
172 XFontSet fontset; 311 XFontSet fontset;
173 Pixel fg; 312 Pixel fg;
174 Pixel bg; 313 Pixel bg;
314 char *inputmethod;
175 } xic_vars_t; 315 } xic_vars_t;
176
177 xic_vars_t xic_vars; 316 xic_vars_t xic_vars;
178 317 XIC xic;
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 318
183 #define res(name, class, representation, field, default_value) \ 319 #define res(name, class, representation, field, default_value) \
184 { name, class, representation, sizeof(xic_vars.field), \ 320 { name, class, representation, sizeof(xic_vars.field), \
185 XtOffsetOf(xic_vars_t, field), XtRString, default_value } 321 XtOffsetOf(xic_vars_t, field), XtRString, default_value }
186 322
187 static XtResource resources[] = 323 static XtResource resources[] =
188 { 324 {
189 /* name class represent'n field default value */ 325 /* name class represent'n field default value */
190 res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, DefaultXIMStyles), 326 #ifdef THIS_IS_X11R6
191 res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, XtDefaultFontSet), 327 res(XtNinputMethod, XtCInputMethod, XtRString, inputmethod, (XtPointer) NULL),
192 res(XtNximForeground, XtCForeground, XtRPixel, fg, XtDefaultForeground), 328 #endif
193 res(XtNximBackground, XtCBackground, XtRPixel, bg, XtDefaultBackground) 329 res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, (XtPointer) DefaultXIMStyles),
330 res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, (XtPointer) XtDefaultFontSet),
331 res(XtNximForeground, XtCForeground, XtRPixel, fg, (XtPointer) XtDefaultForeground),
332 res(XtNximBackground, XtCBackground, XtRPixel, bg, (XtPointer) XtDefaultBackground)
194 }; 333 };
195 334
196 assert (win != 0 && w != NULL && d != NULL); 335
336 xim = DEVICE_X_XIM (d);
197 337
198 if (!xim) 338 if (!xim)
199 { /* No input method? */ 339 {
200 FRAME_X_XIC (f) = NULL; 340 xim_info ("X Input Method open failed. Waiting for an XIM to be enabled.\n");
201 return; 341 return;
202 } 342 }
203 343
344 w = FRAME_X_TEXT_WIDGET (f);
345
346 /*
347 * initialize XIC
348 */
349 if (FRAME_X_XIC (f)) return;
204 XtGetApplicationResources (w, &xic_vars, 350 XtGetApplicationResources (w, &xic_vars,
205 resources, XtNumber (resources), 351 resources, XtNumber (resources),
206 NULL, 0); 352 NULL, 0);
207
208 if (!xic_vars.fontset) 353 if (!xic_vars.fontset)
209 { 354 {
210 stderr_out ("Can't get fontset resource for Input Method\n"); 355 xim_warn ("Can't get fontset resource for Input Method\n");
211 FRAME_X_XIC (f) = NULL; 356 FRAME_X_XIC (f) = NULL;
212 return; 357 return;
213 } 358 }
214 359
360 /* construct xic */
361 XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES(d), NULL);
215 FRAME_X_XIC_STYLE (f) = style = 362 FRAME_X_XIC_STYLE (f) = style =
216 best_style (&xic_vars.styles, DEVICE_X_XIM_STYLES (d)); 363 best_style (&xic_vars.styles, (XIMStyles *)DEVICE_X_XIM_STYLES(d));
217 364
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, 365 p_list = XVaCreateNestedList (0,
221 XNArea, &p_area, 366 XNArea, &p_area,
222 XNSpotLocation, &spot, 367 XNSpotLocation, &spot,
223 XNForeground, xic_vars.fg, 368 XNForeground, xic_vars.fg,
224 XNBackground, xic_vars.bg, 369 XNBackground, xic_vars.bg,
225 XNFontSet, xic_vars.fontset, 370 XNFontSet, xic_vars.fontset,
226 NULL); 371 NULL);
227 372
228 s_list = XVaCreateNestedList (0, 373 s_list = XVaCreateNestedList (0,
229 XNArea, &s_area, 374 XNArea, &s_area,
230 XNForeground, xic_vars.fg, 375 XNForeground, xic_vars.fg,
231 XNBackground, xic_vars.bg, 376 XNBackground, xic_vars.bg,
232 XNFontSet, xic_vars.fontset, 377 XNFontSet, xic_vars.fontset,
233 NULL); 378 NULL);
379
234 FRAME_X_XIC (f) = xic = 380 FRAME_X_XIC (f) = xic =
235 XCreateIC (xim, 381 XCreateIC (xim,
236 XNInputStyle, style, 382 XNInputStyle, style,
237 XNClientWindow, win, 383 XNClientWindow, win,
238 XNFocusWindow, win, 384 XNFocusWindow, win,
239 XNPreeditAttributes, p_list, 385 XNPreeditAttributes, p_list,
240 XNStatusAttributes, s_list, 386 XNStatusAttributes, s_list,
241 NULL); 387 NULL);
242 XFree (p_list); 388 XFree (p_list);
243 XFree (s_list); 389 XFree (s_list);
244 390
245 if (!xic) 391 if (!xic)
246 { 392 {
247 stderr_out ("Warning: XCreateIC failed\n"); 393 xim_warn ("Warning: XCreateIC failed.\n");
248 return; 394 return;
249 } 395 }
250 396
251 if (style & XIMPreeditPosition) 397 if (style & XIMPreeditPosition)
252 { /* Init spot to invalid values */ 398 {
253 XPoint *frame_spot = &(FRAME_X_XIC_SPOT (f)); 399 XPoint *frame_spot = &(FRAME_X_XIC_SPOT(f));
254 frame_spot->x = frame_spot->y = -1; 400 frame_spot->x = frame_spot->y = -1;
255 } 401 }
256 402
257 XIM_SetGeometry (f); 403 XIM_SetGeometry (f);
258 404
259 XSetICFocus (xic); 405 XSetICFocus (xic);
260 406
261 #ifdef DEBUG_XIM 407 #ifdef THIS_IS_X11R6
262 describe_XIC (xic); 408 /* when frame is going to be destroyed (closed) */
409 XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback,
410 XIM_delete_frame, (XtPointer)f);
263 #endif 411 #endif
264 } 412 }
413
265 414
266 void 415 void
267 XIM_SetGeometry (struct frame *f) 416 XIM_SetGeometry (struct frame *f)
268 { 417 {
269 XIC xic = FRAME_X_XIC (f); 418 XIC xic = FRAME_X_XIC (f);
344 } 493 }
345 494
346 void 495 void
347 XIM_focus_event (struct frame *f, int in_p) 496 XIM_focus_event (struct frame *f, int in_p)
348 { 497 {
349 if (FRAME_X_XIC (f)) 498 if (FRAME_X_XIC (f) /* && FRAME_X_XIM_REGISTERED(f) */)
350 (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f)); 499 (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f));
351 } 500 }
352 501
353 #if 0 502 #if 0
354 #define XIM_Composed_Text_BUFSIZE 64 503 #define XIM_Composed_Text_BUFSIZE 64
383 Status status; 532 Status status;
384 int len; 533 int len;
385 int i; 534 int i;
386 XClientMessageEvent new_event; 535 XClientMessageEvent new_event;
387 536
388 try_again: 537 retry:
389 len = XwcLookupString (ic, x_key_event, composed_input_buf.data, 538 len = XwcLookupString (ic, x_key_event, composed_input_buf.data,
390 composed_input_buf.size, &keysym, &status); 539 composed_input_buf.size, &keysym, &status);
391 switch (status) 540 switch (status)
392 { 541 {
393 case XBufferOverflow: 542 case XBufferOverflow:
394 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */ 543 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
395 goto try_again; 544 goto retry;
396 case XLookupChars: 545 case XLookupChars:
397 break; 546 break;
398 default: 547 default:
399 abort (); 548 abort ();
400 } 549 }
635 } 784 }
636 } 785 }
637 return DEFAULTStyle; /* Default Style */ 786 return DEFAULTStyle; /* Default Style */
638 } 787 }
639 788
789 /* These lisp-callable functions will be sealed until xim-leim is needed.
790 Oct 22 1999 - kazz */
791 #if 0
792 /*
793 * External callable function for XIM
794 */
795 DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /*
796 Open the XIC on the frame if XIM is available.
797 Commonly, use this as \(x-open-xim \(selected-frame)).
798 If the frame is not on X device, return signal.
799 If XIC is created successfully return t. If not return nil.
800 */
801 (frame))
802 {
803 struct frame *f;
804
805 CHECK_LIVE_FRAME (frame);
806 f = XFRAME (frame);
807 if (!FRAME_X_P (f))
808 return signal_simple_error ("This frame is not on X device", frame);
809
810 XIM_init_frame (f);
811 return FRAME_X_XIC (f) ? Qt : Qnil;
812 }
813
814 DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /*
815 Close the XIC on the frame if it exists.
816 Commonly, use this as \(x-close-xim \(selected-frame)).
817 If the frame is not on X device, return signal.
818 Otherwise, it destroys the XIC if it exists, then returns t anyway.
819 */
820 (frame))
821 {
822 struct frame *f;
823 struct device *d;
824
825 CHECK_LIVE_FRAME (frame);
826 f = XFRAME (frame);
827 if (!FRAME_X_P (f))
828 return signal_simple_error ("This frame is not on X device", frame);
829
830 d = XDEVICE (FRAME_DEVICE (f));
831 if (DEVICE_X_XIM (d)) {
832 /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */
833 FRAME_X_XIC (XFRAME (f)) = NULL;
834 }
835 return Qt;
836 }
837 #endif /* if 0 */
838
839 void
840 syms_of_input_method_xlib (void)
841 {
842 defsymbol (&Qxim_xlib, "xim-xlib");
843 #if 0 /* see above */
844 DEFSUBR (Fx_open_xim);
845 DEFSUBR (Fx_close_xim);
846 #endif
847 }
640 848
641 void 849 void
642 vars_of_input_method_xlib (void) 850 vars_of_input_method_xlib (void)
643 { 851 {
644 Fprovide (intern ("xim")); 852 Fprovide (intern ("xim"));