comparison src/input-method-xlib.c @ 428:3ecd8885ac67 r21-2-22

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