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