1 /* Various functions for X11R5+ input methods, using the Xlib interface.
2 Copyright (C) 1996 Sun Microsystems.
4 This file is part of SXEmacs
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: Not in FSF. */
22 /* Written by Martin Buchholz. */
24 /* This file implements an interface to X input methods, available
25 with X11R5 and above. See O'Reilly, Xlib programmer's guide,
26 and X11 R6 release guide chapters on internationalized input,
27 for further details */
32 The XIM is of the device, by the device, for the device.
33 The XIC is of each frame, by each frame, for each frame.
35 1. Activate XICs on poor frames when the XIM is back.
36 2. Deactivate all the XICs when the XIM goes down.
40 - Register a callback for an XIM when the X device is being initialized.
41 XIM_init_device (d) { XRegisterIMInstantiateCallback (); }
42 The "XRegisterIMInstantiateCallback" is called when an XIM become
43 available on the X display.
45 - Catch the XIC when the frame is being initialized if XIM was available.
46 XIM_init_frame (f) { ... XCreateIC (); ... }
48 - Release the XIC when the frame is being closed.
49 XIM_delete_frame (f) { ... FRAME_X_XIC (f) = NULL; ... }
50 "XIM_delete_frame" is a "DestroyCallback" function declared in
53 - Release all the XICs when the XIM was down accidentally.
55 DEVICE_FRAME_LOOP (...) { FRAME_X_XIC (f) = NULL; }
57 - Re-enable XIC for all the frames which don't have XIC when the XIM
59 In IMInstantiateCallback:
60 DEVICE_FRAME_LOOP (...) { XIM_init_frame (f); }
65 - Currently, we don't use XDestroyIC because of _XimProtoCloseIM
66 (internally registered as im->methods->close) does "Xfree (ic)".
72 #include <X11/Xlocale.h> /* More portable than <locale.h> ? */
75 #include "ui/device.h"
76 #include "ui/window.h"
78 #include "ui/X11/console-x.h"
79 #include "ui/X11/EmacsFrame.h"
80 #define INCLUDE_EVENTS_H_PRIVATE_SPHERE
81 #include "events/events.h"
83 #if !defined (XIM_XLIB) && !defined (USE_XFONTSET)
84 #error neither XIM_XLIB nor USE_XFONTSET is defined??
87 Lisp_Object Qxim_xlib;
88 #define xim_warn(str) warn_when_safe (Qxim_xlib, Qwarning, str);
89 #define xim_warn1(fmt, str) warn_when_safe (Qxim_xlib, Qwarning, fmt, str);
90 #define xim_info(str) warn_when_safe (Qxim_xlib, Qinfo, str);
92 #ifdef XIM_XLIB /* XIM_XLIB specific */
93 /* Get/Set IC values for just one attribute */
95 #define XIC_Value(Get_Set, xic, name, attr, value) \
98 XVaNestedList list = XVaCreateNestedList( \
99 0, attr, value, NULL); \
100 if ((bad_arg = X##Get_Set##ICValues( \
101 xic, name, list, NULL)) != NULL) \
102 stderr_out ("X" #Get_Set "ICValues " \
103 "bad Arg: %s\n", bad_arg); \
106 #else /* ! DEBUG_SXEMACS */
107 #define XIC_Value(Get_Set, xic, name, attr, value) \
109 XVaNestedList list = XVaCreateNestedList( \
110 0, attr, value, NULL); \
111 X##Get_Set##ICValues (xic, name, list, NULL); \
114 #endif /* DEBUG_SXEMACS */
116 static char DefaultXIMStyles[] =
117 "XIMPreeditPosition|XIMStatusArea\n"
118 "XIMPreeditPosition|XIMStatusNone\n"
119 "XIMPreeditPosition|XIMStatusNothing\n"
120 "XIMPreeditNothing|XIMStatusArea\n"
121 "XIMPreeditNothing|XIMStatusNothing\n"
122 "XIMPreeditNothing|XIMStatusNone\n"
123 "XIMPreeditNone|XIMStatusArea\n"
124 "XIMPreeditNone|XIMStatusNothing\n"
125 "XIMPreeditNone|XIMStatusNone";
127 static XIMStyle best_style (XIMStyles *user, XIMStyles *xim);
128 #endif /* XIM_XLIB only */
130 /* This function is documented, but no prototype in the header files */
131 EXTERN_C char * XSetIMValues(XIM, ...);
134 Initialize_Locale (void)
138 /* dverna - Nov. 98: #### DON'T DO THIS !!! The default XtLanguageProc
139 routine calls setlocale(LC_ALL, lang) which fucks up our lower-level
140 locale management, and especially the value of LC_NUMERIC. Anyway,
141 since at this point, we don't know yet whether we're gonna need an
142 X11 frame, we should really do it manually and not use Xlib's dumb
144 /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/
145 if ((locale = setlocale (LC_ALL, "")) == NULL) {
146 xim_warn ("Can't set locale.\n"
147 "Using C locale instead.\n");
150 if ((locale = setlocale (LC_ALL, "C")) == NULL) {
151 xim_warn ("Can't even set locale to `C'!\n");
156 if (!XSupportsLocale ()) {
157 xim_warn1 ("X Windows does not support locale `%s'\n"
158 "Using C Locale instead\n", locale);
161 if (setlocale (LC_ALL, "C") == NULL) {
162 xim_warn ("Can't set locale to `C'!\n");
165 if (!XSupportsLocale ()) {
166 xim_warn ("X Windows does not support locale `C'!\n");
171 setlocale(LC_NUMERIC, "C");
173 if (XSetLocaleModifiers ("") == NULL) {
174 xim_warn ("XSetLocaleModifiers(\"\") failed\n"
175 "Check the value of the XMODIFIERS "
176 "environment variable.\n");
180 #ifdef XIM_XLIB /* starting XIM specific codes */
182 /* Callbacks for IM are supported from X11R6 or later. */
183 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK
185 static Boolean xim_initted = False;
187 /* Called from when XIM is destroying.
188 Clear all the XIC when the XIM was destroying... */
190 IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data)
192 struct device *d = (struct device *)client_data;
195 DEVICE_FRAME_LOOP (tail, d) {
196 struct frame *target_frame = XFRAME (XCAR (tail));
197 if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame)) {
198 /* XDestroyIC (FRAME_X_XIC (target_frame)); */
199 FRAME_X_XIC (target_frame) = NULL;
203 DEVICE_X_XIM (d) = NULL;
208 /* This is registered in XIM_init_device (when DEVICE is initializing).
209 This activates XIM when XIM becomes available. */
211 IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
213 struct device *d = (struct device *)client_data;
216 XIMCallback ximcallback;
219 /* if no xim is presented, initialize xim ... */
220 if ( xim_initted == False ) {
222 XtGetApplicationNameAndClass (dpy, &name, &class);
223 DEVICE_X_XIM (d) = xim =
224 XOpenIM (dpy, XtDatabase (dpy), name, class);
226 /* destroy callback for im */
227 ximcallback.callback = (XIMProc) IMDestroyCallback;
228 ximcallback.client_data = (XPointer) d;
229 XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
232 /* activate XIC on all the X frames... */
233 DEVICE_FRAME_LOOP (tail, d) {
234 struct frame *target_frame = XFRAME (XCAR (tail));
235 if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame)) {
236 XIM_init_frame (target_frame);
241 #endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
243 /* Initialize XIM for X device.
244 Register the use of XIM using XRegisterIMInstantiateCallback. */
246 XIM_init_device (struct device *d)
248 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK /* X11R6+ */
249 DEVICE_X_XIM (d) = NULL;
250 XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL,
251 #ifdef XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE
252 /* The sixth parameter is of type
253 XPointer in XFree86 but (XPointer *)
254 on most other X11's. */
255 (XIDProc) IMInstantiateCallback,
257 #else /* X Consortium prototype */
258 (XIMProc) IMInstantiateCallback,
260 #endif /* XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE */
263 #else /* pre-X11R6 */
264 Display *dpy = DEVICE_X_DISPLAY (d);
268 XtGetApplicationNameAndClass (dpy, &name, &class);
269 DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
271 xim_warn ("XOpenIM() failed...no input server available\n");
274 XGetIMValues (xim, XNQueryInputStyle,
275 &DEVICE_X_XIM_STYLES (d), NULL);
278 #endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
286 /* Callback for the deleting frame. */
288 XIM_delete_frame (Widget w, XtPointer client_data, XtPointer call_data)
290 struct frame *f = (struct frame *) client_data;
291 struct device *d = XDEVICE (FRAME_DEVICE (f));
293 if (DEVICE_X_XIM (d)) {
294 if (FRAME_X_XIC (f)) {
295 XDestroyIC (FRAME_X_XIC (f));
296 FRAME_X_XIC (f) = NULL;
302 /* Initialize XIC for new frame.
303 Create an X input context (XIC) for this frame. */
305 XIM_init_frame (struct frame *f)
307 struct device *d = XDEVICE (FRAME_DEVICE (f));
309 Widget w = FRAME_X_TEXT_WIDGET (f);
310 Window win = XtWindow (w);
311 XRectangle p_area = {0,0,1,1}, s_area = {0,0,1,1};
314 XVaNestedList p_list, s_list;
326 #define res(name, class, representation, field, default_value) \
327 { name, class, representation, sizeof(xic_vars.field), \
328 XtOffsetOf(xic_vars_t, field), XtRString, \
331 static XtResource resources[] =
333 /* name class represent'n field default value */
334 res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, (XtPointer) DefaultXIMStyles),
335 res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, (XtPointer) XtDefaultFontSet),
336 res(XtNximForeground, XtCForeground, XtRPixel, fg, (XtPointer) XtDefaultForeground),
337 res(XtNximBackground, XtCBackground, XtRPixel, bg, (XtPointer) XtDefaultBackground)
341 xim = DEVICE_X_XIM (d);
347 w = FRAME_X_TEXT_WIDGET (f);
352 if (FRAME_X_XIC (f)) {
355 XtGetApplicationResources (w, &xic_vars,
356 resources, XtNumber (resources),
358 if (!xic_vars.fontset) {
359 xim_warn ("Can't get fontset resource for Input Method\n");
360 FRAME_X_XIC (f) = NULL;
365 XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES(d), NULL);
366 FRAME_X_XIC_STYLE (f) = style =
367 best_style (&xic_vars.styles,
368 (XIMStyles *)DEVICE_X_XIM_STYLES(d));
370 p_list = XVaCreateNestedList (0,
372 XNSpotLocation, &spot,
373 XNForeground, xic_vars.fg,
374 XNBackground, xic_vars.bg,
375 XNFontSet, xic_vars.fontset,
378 s_list = XVaCreateNestedList (0,
380 XNForeground, xic_vars.fg,
381 XNBackground, xic_vars.bg,
382 XNFontSet, xic_vars.fontset,
385 FRAME_X_XIC (f) = xic =
390 XNPreeditAttributes, p_list,
391 XNStatusAttributes, s_list,
397 xim_warn ("Warning: XCreateIC failed.\n");
401 if (style & XIMPreeditPosition) {
402 XPoint *frame_spot = &(FRAME_X_XIC_SPOT(f));
403 frame_spot->x = frame_spot->y = -1;
410 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK
411 /* when frame is going to be destroyed (closed) */
412 XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback,
413 XIM_delete_frame, (XtPointer)f);
419 XIM_SetGeometry (struct frame *f)
428 xic = FRAME_X_XIC (f);
433 style = FRAME_X_XIC_STYLE (f);
435 if (style & XIMStatusArea) {
436 /* Place Status Area in bottom right corner */
437 /* Negotiate geometry of status area */
438 /* See O'Reilly Xlib XIM chapter (but beware, it's buggy) */
441 /* If input method has existing status area, use its current
443 /* The following at least works for Sun's htt */
444 area.x = area.y = area.width = area.height = 0;
445 XIC_Value (Set, xic, XNStatusAttributes, XNAreaNeeded, &area);
446 XIC_Value (Get, xic, XNStatusAttributes, XNAreaNeeded, &needed);
447 if (needed->width == 0) {
448 /* Use XNArea instead of XNAreaNeeded */
449 XIC_Value (Get, xic, XNStatusAttributes,
452 area.width = needed->width;
453 area.height = needed->height;
454 area.x = FRAME_RIGHT_BORDER_START (f) - area.width;
455 area.y = FRAME_BOTTOM_BORDER_START (f) - area.height;
458 stderr_out ("Putting StatusArea in x=%d y=%d w=%d h=%d\n",
459 area.x, area.y, area.width, area.height);
460 #endif /* DEBUG_XIM */
462 XIC_Value (Set, xic, XNStatusAttributes, XNArea, &area);
465 if (style & XIMPreeditPosition) {
466 /* Set Preedit Area to whole frame size (sans border) */
467 /* We include the border because Preedit window might be larger
468 than display line at edge. #### FIX: we should adjust to make
469 sure that there is always room for the spot sub-window */
470 area.x = FRAME_LEFT_BORDER_START (f);
471 area.y = FRAME_TOP_BORDER_START (f);
472 area.width = FRAME_RIGHT_BORDER_END (f) - area.x;
473 area.height = FRAME_BOTTOM_BORDER_END (f) - area.y;
474 XIC_Value(Set, xic, XNPreeditAttributes, XNArea, &area);
483 XIM_SetSpotLocation (struct frame *f, int x, int y)
485 XIC xic = FRAME_X_XIC (f);
486 XPoint *spot = &(FRAME_X_XIC_SPOT (f));
488 /* Only care if we have a valid XIC using Over the Spot in
489 * a different location */
491 !(FRAME_X_XIC_STYLE (f) & XIMPreeditPosition) ||
492 (spot->x == (short) x &&
493 spot->y == (short) y)) {
499 /* #### FIX: Must make sure spot fits within Preedit Area */
500 XIC_Value (Set, xic, XNPreeditAttributes, XNSpotLocation, spot);
502 stderr_out ("Spot: %d %d\n", spot->x, spot->y);
507 XIM_focus_event (struct frame *f, int in_p)
509 if (FRAME_X_XIC (f) /* && FRAME_X_XIM_REGISTERED(f) */) {
510 (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f));
515 #define XIM_Composed_Text_BUFSIZE 64
516 typedef struct XIM_Composed_Text
519 wchar_t data [XIM_Composed_Text_BUFSIZE];
522 static XIM_Composed_Text composed_input_buf = {XIM_Composed_Text_BUFSIZE, {0}};
525 /* get_XIM_input -- Process results of input method composition.
527 This function copies the results of the input method composition to
528 composed_input_buf. Then for each character, a custom event of type
529 wc_atom is sent with the character as its data.
531 It is probably more efficient to copy the composition results to some
532 allocated memory and send a single event pointing to that memory.
533 That would cut down on the event processing as well as allow quick
534 insertion into the buffer of the whole string. It might require some
535 care, though, to avoid fragmenting memory through the allocation and
536 freeing of many small chunks. Maybe the existing system for
537 (single-byte) string allocation can be used, multiplying the length by
538 sizeof (wchar_t) to get the right size. */
541 get_XIM_input (XKeyPressedEvent *x_key_event, XIC ic, Display *dpy)
547 XClientMessageEvent new_event;
550 len = XwcLookupString (ic, x_key_event, composed_input_buf.data,
551 composed_input_buf.size, &keysym, &status);
553 case XBufferOverflow:
554 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
562 new_event.type = ClientMessage;
563 new_event.display = x_key_event->display;
564 new_event.window = x_key_event->window;
565 new_event.message_type = wc_atom;
566 new_event.format = 32; /* 32-bit wide data */
567 new_event.data.l[2] = new_event.data.l[3] = new_event.data.l[4] = 0L;
568 new_event.data.l[0] = x_key_event->time;
569 for (i = 0; i < len; i++) {
570 new_event.data.l[1] = ((wchar_t *) composed_input_buf.data)[i];
571 XSendEvent (display, main_window, False, 0L,
572 (XEvent *) &new_event);
577 /* ============================================================== */
578 /* X input method style determination */
579 /* ============================================================== */
582 #define done(type, value) \
583 if (toVal->addr != NULL) { \
584 if (toVal->size < sizeof(type)) { \
585 toVal->size = sizeof(type); \
588 *(type*)toVal->addr = (value); \
590 static type static_val; \
591 static_val = (value); \
592 toVal->addr = (XPointer)&static_val; \
594 toVal->size = sizeof(type); \
595 return True /* Caller supplies `;' */
599 * This is a standard Xt type converter, except that the caller MUST
600 * supply a proper non-NULL toVal XIMStyles structure that we will
603 * fromVal points to a string like
605 "XIMPreeditPosition|XIMStatusArea,
606 XIMPreeditPosition|XIMStatusNothing
607 XIMPreeditNothing|XIMStatusNothing"
609 * This is converted in the obvious way to a XIMStyles structure.
611 * mrb: #### Fix this to handle Motif-style specifications for
612 * XIMStyles as well: overTheSpot, rootWindow, none */
614 /* XtTypeConverter */
616 EmacsXtCvtStringToXIMStyles (
622 XtPointer *converter_data)
624 #define STYLE_INFO(style) { style, #style, sizeof(#style) }
625 static struct XIMStyleInfo {
626 const XIMStyle style;
627 const char * const name;
629 } emacs_XIMStyleInfo[] = {
630 STYLE_INFO (XIMPreeditPosition|XIMStatusArea),
631 STYLE_INFO (XIMPreeditPosition|XIMStatusNothing),
632 STYLE_INFO (XIMPreeditPosition|XIMStatusNone),
633 STYLE_INFO (XIMPreeditNothing|XIMStatusArea),
634 STYLE_INFO (XIMPreeditNothing|XIMStatusNothing),
635 STYLE_INFO (XIMPreeditNothing|XIMStatusNone),
636 STYLE_INFO (XIMPreeditNone|XIMStatusArea),
637 STYLE_INFO (XIMPreeditNone|XIMStatusNothing),
638 STYLE_INFO (XIMPreeditNone|XIMStatusNone)
642 char *s = (char *) fromVal->addr;
643 char *end = s + fromVal->size;
644 XIMStyles * const p = (XIMStyles *) toVal->addr;
645 const char * const delimiter = " \t\n\r:;," ;
646 const int max_styles = XtNumber(emacs_XIMStyleInfo);
651 stderr_out ("EmacsCvtStringToXIMStyles called with "
652 "size=%d, string=\"%s\"\n",
653 fromVal->size, (char *) fromVal->addr);
654 #endif /* DEBUG_XIM */
656 if (*num_args != 0) {
657 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
658 XtAppWarningMsg(the_app_con, "wrongParameters",
659 "cvtStringToXIMStyle",
661 "String to XIMStyle conversion requires "
662 "exactly 0 parameters",
663 (String *)NULL, (Cardinal *)NULL);
668 /* Make sure caller is giving us good data */
669 assert (fromVal->addr != NULL);
670 assert (fromVal->size == strlen(fromVal->addr)+1);
671 assert (toVal->addr != NULL);
672 assert (toVal->size == sizeof(XIMStyles));
673 #endif /* DEBUG_SXEMACS */
676 p->supported_styles = xnew_atomic_array(XIMStyle, max_styles);
679 * The following routine assumes that the style name resource is
680 * identical with the programmatic name of style. For example,
681 * "XIMPreeditPosition|XIMStatusArea" means the
682 * XIMPreeditPosition|XIMStatusArea value is specified. If the
683 * style name is changed, such as "OverTheSpot|imDisplaysInClient",
684 * the parsing logic below should be modified as well. */
686 if ((c = strtok(s, delimiter)) == NULL) {
690 for(i=0 ; i<max_styles ; i++) {
691 struct XIMStyleInfo *rec = emacs_XIMStyleInfo + i;
692 if(!strncmp(c, rec->name, rec->namelen - 1)) {
693 p->supported_styles[p->count_styles] =
699 if((c = strtok(NULL, delimiter)) == NULL) {
704 if (p->count_styles == 0) {
705 /* No valid styles? */
706 char buf[strlen(fromVal->addr) +
707 strlen(DefaultXIMStyles) +
711 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
713 len = snprintf(buf, sizeof(buf),
714 "Cannot convert string \"%s\" to type XIMStyles.\n"
715 "Using default string \"%s\" instead.\n",
716 fromVal->addr, DefaultXIMStyles);
717 assert(len >= 0 && (size_t)len < sizeof(buf));
718 XtAppWarningMsg(the_app_con, "wrongParameters",
719 "cvtStringToXIMStyle",
721 buf, (String *)NULL, (Cardinal *)NULL);
722 new_from.addr = DefaultXIMStyles;
723 new_from.size = sizeof(DefaultXIMStyles);
724 return EmacsXtCvtStringToXIMStyles (dpy, args, num_args,
728 XREALLOC_ARRAY (p->supported_styles, XIMStyle, p->count_styles);
729 *converter_data = (char *) True;
738 XtPointer converter_data,
743 stderr_out ("Converter data: %x\n", converter_data);
744 stderr_out ("EmacsFreeXIMStyles called\n");
745 #endif /* DEBUG_XIM */
747 if (*num_args != 0) {
748 XtAppWarningMsg(app, "wrongParameters", "freeXIMStyles",
750 "Freeing an XIMStyles requires that "
751 "zero arguments be passwd",
752 (String *)NULL, (Cardinal *)NULL);
756 if (converter_data) {
757 Boolean free_p = (Boolean) (EMACS_INT)converter_data;
758 XIMStyles *free_me = (XIMStyles *) toVal->addr;
760 /* use our free function */
761 xfree(free_me->supported_styles);
767 /* O'Reilly XLib Programming Manual, pg. 371 */
768 /* Much nicer implementation than O'Reilly */
769 /* Choose the more `complicated', hence nicer, XIM input style */
771 BetterStyle (XIMStyle s, XIMStyle t)
773 #define CHECK_XIMStyle_BIT(bit) \
774 if ((s ^ t) & bit) { return (s & bit) ? s : t; }
776 CHECK_XIMStyle_BIT (XIMPreeditCallbacks);
777 CHECK_XIMStyle_BIT (XIMPreeditPosition);
778 CHECK_XIMStyle_BIT (XIMPreeditArea);
779 CHECK_XIMStyle_BIT (XIMPreeditNothing);
780 CHECK_XIMStyle_BIT (XIMStatusCallbacks);
781 CHECK_XIMStyle_BIT (XIMStatusArea);
782 CHECK_XIMStyle_BIT (XIMStatusNothing);
783 #undef CHECK_XIMStyle_BIT
788 /* Choose the best style, given:
789 * - user preferences (already checked to be supported by SXEmacs)
790 * - styles supported by the input method */
791 #define DEFAULTStyle (XIMPreeditNothing|XIMStatusNothing)
793 best_style (XIMStyles *user, XIMStyles *xim)
796 for (i=0 ; i<user->count_styles ; i++) {
797 for (j=0 ; j<xim->count_styles ; j++) {
798 if (user->supported_styles[i] ==
799 xim->supported_styles[j]) {
800 return user->supported_styles[i];
804 return DEFAULTStyle; /* Default Style */
807 /* These lisp-callable functions will be sealed until xim-leim is needed.
808 Oct 22 1999 - kazz */
811 * External callable function for XIM
813 DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /*
814 Open the XIC on the frame if XIM is available.
815 Commonly, use this as \(x-open-xim \(selected-frame)).
816 If the frame is not on X device, return signal.
817 If XIC is created successfully return t. If not return nil.
823 CHECK_LIVE_FRAME (frame);
825 if (!FRAME_X_P (f)) {
826 return signal_simple_error(
827 "This frame is not on X device", frame);
830 return FRAME_X_XIC (f) ? Qt : Qnil;
833 DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /*
834 Close the XIC on the frame if it exists.
835 Commonly, use this as \(x-close-xim \(selected-frame)).
836 If the frame is not on X device, return signal.
837 Otherwise, it destroys the XIC if it exists, then returns t anyway.
844 CHECK_LIVE_FRAME (frame);
846 if (!FRAME_X_P (f)) {
847 return signal_simple_error(
848 "This frame is not on X device", frame);
850 d = XDEVICE (FRAME_DEVICE (f));
851 if (DEVICE_X_XIM (d)) {
852 /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */
853 FRAME_X_XIC (XFRAME (f)) = NULL;
860 syms_of_input_method_xlib (void)
862 defsymbol (&Qxim_xlib, "xim-xlib");
863 #if 0 /* see above */
864 DEFSUBR (Fx_open_xim);
865 DEFSUBR (Fx_close_xim);
870 vars_of_input_method_xlib (void)
872 Fprovide (intern ("xim"));
876 /* ====================================================================== */
877 /* Internal Debugging Routines */
878 /* ====================================================================== */
882 describe_XIM (XIM xim)
886 /* Print locale of XIM */
887 stderr_out ("\nXIM Locale of IM: %s\n", XLocaleOfIM(xim));
889 /* List supported input method styles */
890 XGetIMValues(xim, XNQueryInputStyle, &styles, NULL);
892 stderr_out ("\n%d input style(s) supported by input method.\n",
893 styles->count_styles);
896 for (int i=0; i < styles->count_styles; i++) {
897 describe_XIMStyle (styles->supported_styles[i]);
899 #endif /* DEBUG_XIM */
904 describe_XFontSet (XFontSet fontset)
906 XFontStruct **font_struct_list;
907 char **font_name_list;
910 if (fontset == NULL) {
911 stderr_out ("NULL\n");
915 count = XFontsOfFontSet(fontset, &font_struct_list, &font_name_list);
916 stderr_out ( "%d font(s) available:\n", count);
917 for (i=0 ; i < count ; i++) {
918 stderr_out ("Font: %s\n", *(font_name_list+i));
923 describe_Status (Status status)
925 #define DESCRIBE_STATUS(value) \
926 if (status == value) { \
927 stderr_out ("Status: " #value "\n"); \
930 DESCRIBE_STATUS (XBufferOverflow);
931 DESCRIBE_STATUS (XLookupNone);
932 DESCRIBE_STATUS (XLookupKeySym);
933 DESCRIBE_STATUS (XLookupBoth);
934 DESCRIBE_STATUS (XLookupChars);
935 #undef DESCRIBE_STATUS
939 describe_Window (Window win)
942 int sz = snprintf (xwincmd, sizeof(xwincmd),
943 "xwininfo -id 0x%x >&2; xwininfo -events -id 0x%x >&2",
944 (int) win, (int) win);
945 if ( sz >= 0 && (size_t) sz < sizeof(xwincmd) ) {
946 int exit_code = system (xwincmd);
947 if ( exit_code != 0 )
948 stderr_out("command '%s' failed with exit code %d",
951 stderr_out("Could not generate wininfo command line");
955 describe_XIC (XIC xic)
958 Window client_win=0, focus_win=0;
959 char *resourceName = NULL;
960 char *resourceClass = NULL;
961 char *bad_arg = NULL;
962 unsigned long filter_mask = NoEventMask;
963 XVaNestedList p_list, s_list;
964 XFontSet p_fontset = NULL, s_fontset = NULL;
965 Pixel p_fg=0, p_bg = 0, s_fg=0, s_bg = 0;
966 XRectangle *p_area = NULL, *s_area = NULL;
967 XRectangle *p_needed = NULL, *s_needed = NULL;
968 XPoint *p_spot = NULL;
970 /* Check for valid input context and method */
972 stderr_out ("Input method is NULL\n");
975 stderr_out ("XIMOfIC() returns NULL\n");
977 /* Print out Input Context Attributes */
978 p_list = XVaCreateNestedList (0,
979 XNFontSet, &p_fontset,
981 XNAreaNeeded, &p_needed,
982 XNSpotLocation, &p_spot,
987 s_list = XVaCreateNestedList (0,
988 XNFontSet, &s_fontset,
990 XNAreaNeeded, &s_needed,
995 bad_arg = XGetICValues(xic,
996 XNInputStyle, &style,
997 XNFilterEvents, &filter_mask,
998 XNClientWindow, &client_win,
999 XNFocusWindow, &focus_win,
1000 XNResourceName, &resourceName,
1001 XNResourceClass, &resourceClass,
1002 XNPreeditAttributes, p_list,
1003 XNStatusAttributes, s_list,
1008 if (bad_arg != NULL) {
1009 stderr_out ("Couldn't get IC value: %s\n", bad_arg);
1011 stderr_out ("\nInput method context attributes:\n");
1012 stderr_out ("Style: "); describe_XIMStyle (style);
1013 stderr_out ("Client window: %lx\n", (unsigned long int)client_win);
1014 stderr_out ("Focus window: %lx\n", (unsigned long int)focus_win);
1015 stderr_out ("Preedit:\n");
1016 describe_XRectangle (" Area", p_area);
1017 describe_XRectangle (" Area needed", p_needed);
1018 stderr_out (" foreground: %lx\n", (unsigned long int)p_fg);
1019 stderr_out (" background: %lx\n", (unsigned long int)p_bg);
1020 stderr_out (" fontset: "); describe_XFontSet (p_fontset);
1021 stderr_out ("Status:\n");
1022 describe_XRectangle (" Area", s_area);
1023 describe_XRectangle (" Area needed", s_needed);
1024 stderr_out (" foreground: %lx\n", (unsigned long int)s_fg);
1025 stderr_out (" background: %lx\n", (unsigned long int)s_bg);
1026 stderr_out (" fontset: \n"); describe_XFontSet (s_fontset);
1027 stderr_out ("XNResourceName: %s\n", resourceName
1028 ? resourceName : "NULL");
1029 stderr_out ("XNResourceClass: %s\n", resourceClass
1030 ? resourceClass : "NULL");
1031 stderr_out ("XNFilterEvents: "); describe_event_mask (filter_mask);
1035 describe_XRectangle (char *name, XRectangle *r)
1038 stderr_out ("%s: NULL\n", name);
1040 stderr_out ("%s: x=%d y=%d w=%d h=%d\n",
1041 name, r->x, r->y, r->width, r->height);
1045 /* Print out elements of Event mask */
1046 /* Defines from X11/X.h */
1048 describe_event_mask (unsigned long mask)
1050 #define DESCRIBE_EVENT_MASK(bit) if ((bit) & mask) stderr_out (#bit " ")
1051 DESCRIBE_EVENT_MASK (NoEventMask);
1052 DESCRIBE_EVENT_MASK (KeyPressMask);
1053 DESCRIBE_EVENT_MASK (KeyReleaseMask);
1054 DESCRIBE_EVENT_MASK (ButtonPressMask);
1055 DESCRIBE_EVENT_MASK (ButtonReleaseMask);
1056 DESCRIBE_EVENT_MASK (EnterWindowMask);
1057 DESCRIBE_EVENT_MASK (LeaveWindowMask);
1058 DESCRIBE_EVENT_MASK (PointerMotionMask);
1059 DESCRIBE_EVENT_MASK (PointerMotionHintMask);
1060 DESCRIBE_EVENT_MASK (Button1MotionMask);
1061 DESCRIBE_EVENT_MASK (Button2MotionMask);
1062 DESCRIBE_EVENT_MASK (Button3MotionMask);
1063 DESCRIBE_EVENT_MASK (Button4MotionMask);
1064 DESCRIBE_EVENT_MASK (Button5MotionMask);
1065 DESCRIBE_EVENT_MASK (ButtonMotionMask);
1066 DESCRIBE_EVENT_MASK (KeymapStateMask);
1067 DESCRIBE_EVENT_MASK (ExposureMask);
1068 DESCRIBE_EVENT_MASK (VisibilityChangeMask);
1069 DESCRIBE_EVENT_MASK (StructureNotifyMask);
1070 DESCRIBE_EVENT_MASK (ResizeRedirectMask);
1071 DESCRIBE_EVENT_MASK (SubstructureNotifyMask);
1072 DESCRIBE_EVENT_MASK (SubstructureRedirectMask);
1073 DESCRIBE_EVENT_MASK (FocusChangeMask);
1074 DESCRIBE_EVENT_MASK (PropertyChangeMask);
1075 DESCRIBE_EVENT_MASK (ColormapChangeMask);
1076 DESCRIBE_EVENT_MASK (OwnerGrabButtonMask);
1077 #undef DESCRIBE_EVENT_MASK
1082 describe_XIMStyle (XIMStyle style)
1084 #define DESCRIBE_STYLE(bit) \
1085 if (bit & style) { \
1086 stderr_out (#bit " "); \
1089 DESCRIBE_STYLE (XIMPreeditArea);
1090 DESCRIBE_STYLE (XIMPreeditCallbacks);
1091 DESCRIBE_STYLE (XIMPreeditPosition);
1092 DESCRIBE_STYLE (XIMPreeditNothing);
1093 DESCRIBE_STYLE (XIMPreeditNone);
1094 DESCRIBE_STYLE (XIMStatusArea);
1095 DESCRIBE_STYLE (XIMStatusCallbacks);
1096 DESCRIBE_STYLE (XIMStatusNothing);
1097 DESCRIBE_STYLE (XIMStatusNone);
1098 #undef DESCRIBE_STYLE
1103 describe_XIMStyles (XIMStyles *p)
1106 stderr_out ("%d Style(s):\n", p->count_styles);
1107 for (i=0; i<p->count_styles ; i++) {
1108 describe_XIMStyle (p->supported_styles[i]);
1112 #endif /* DEBUG_SXEMACS */
1114 /* Random cruft follows */
1118 Unit_Test (struct frame *f, char * s)
1119 /* mrb unit testing */
1121 XrmValue fromVal, toVal;
1124 fromVal.size = strlen (s);
1125 toVal.addr = (XtPointer) &user_preferred_XIMStyles;
1126 toVal.size = sizeof (XIMStyles);
1128 if (XtConvertAndStore (FRAME_X_TEXT_WIDGET (f), XtRString, &fromVal,
1129 XtRXimStyles, &toVal) != False) {
1130 stderr_out ("Unit_Test: fromVal.addr=0x%x\n",fromVal.addr);
1131 stderr_out ("Unit_Test: fromVal.size=%d\n", fromVal.size);
1132 stderr_out ("Unit_Test: toVal.addr=0x%x\n", toVal.addr);
1133 stderr_out ("Unit_Test: toVal.size=%d\n", toVal.size);
1134 describe_XIMStyles ((XIMStyles *) toVal.addr);
1138 #endif /* XIM_XLIB only */
1141 /* Get a fontset for IM to use */
1143 x_init_fontset (struct device *d)
1145 Display *dpy = DEVICE_X_DISPLAY (d);
1147 char ** missing_charsets;
1148 int num_missing_charsets;
1149 char * default_string;
1150 /* char * font_set_string = "-dt-interface user-medium-r-normal\
1151 -s*-*-*-*-*-*-*-*-*";*/
1152 char *font_set_string =
1153 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*,"
1154 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0,"
1155 "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,"
1156 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0";
1158 DEVICE_X_FONTSET (d) = fontset =
1159 XCreateFontSet (dpy, font_set_string,
1161 &num_missing_charsets,
1164 if (fontset == NULL) {
1165 stderr_out("Unable to create fontset from string:\n%s\n",
1169 if (num_missing_charsets > 0) {
1171 stderr_out ("\nMissing charsets for fontset %s:\n",
1173 for (i=0; i < num_missing_charsets; i++) {
1174 stderr_out ("%s\n", missing_charsets[i]);
1176 XFreeStringList (missing_charsets);
1177 stderr_out ("Default string: %s\n", default_string);
1181 describe_XFontSet (fontset);