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 "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 ((locale = 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) +
710 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
712 sprintf(buf, "Cannot convert string \"%s\" to type XIMStyles.\n"
713 "Using default string \"%s\" instead.\n",
714 fromVal->addr, DefaultXIMStyles);
715 XtAppWarningMsg(the_app_con, "wrongParameters",
716 "cvtStringToXIMStyle",
718 buf, (String *)NULL, (Cardinal *)NULL);
719 new_from.addr = DefaultXIMStyles;
720 new_from.size = sizeof(DefaultXIMStyles);
721 return EmacsXtCvtStringToXIMStyles (dpy, args, num_args,
725 XREALLOC_ARRAY (p->supported_styles, XIMStyle, p->count_styles);
726 *converter_data = (char *) True;
735 XtPointer converter_data,
740 stderr_out ("Converter data: %x\n", converter_data);
741 stderr_out ("EmacsFreeXIMStyles called\n");
742 #endif /* DEBUG_XIM */
744 if (*num_args != 0) {
745 XtAppWarningMsg(app, "wrongParameters", "freeXIMStyles",
747 "Freeing an XIMStyles requires that "
748 "zero arguments be passwd",
749 (String *)NULL, (Cardinal *)NULL);
753 if (converter_data) {
754 Boolean free_p = (Boolean) (EMACS_INT)converter_data;
755 XIMStyles *free_me = (XIMStyles *) toVal->addr;
757 /* use our free function */
758 xfree(free_me->supported_styles);
764 /* O'Reilly XLib Programming Manual, pg. 371 */
765 /* Much nicer implementation than O'Reilly */
766 /* Choose the more `complicated', hence nicer, XIM input style */
768 BetterStyle (XIMStyle s, XIMStyle t)
770 #define CHECK_XIMStyle_BIT(bit) \
771 if ((s ^ t) & bit) { return (s & bit) ? s : t; }
773 CHECK_XIMStyle_BIT (XIMPreeditCallbacks);
774 CHECK_XIMStyle_BIT (XIMPreeditPosition);
775 CHECK_XIMStyle_BIT (XIMPreeditArea);
776 CHECK_XIMStyle_BIT (XIMPreeditNothing);
777 CHECK_XIMStyle_BIT (XIMStatusCallbacks);
778 CHECK_XIMStyle_BIT (XIMStatusArea);
779 CHECK_XIMStyle_BIT (XIMStatusNothing);
780 #undef CHECK_XIMStyle_BIT
785 /* Choose the best style, given:
786 * - user preferences (already checked to be supported by SXEmacs)
787 * - styles supported by the input method */
788 #define DEFAULTStyle (XIMPreeditNothing|XIMStatusNothing)
790 best_style (XIMStyles *user, XIMStyles *xim)
793 for (i=0 ; i<user->count_styles ; i++) {
794 for (j=0 ; j<xim->count_styles ; j++) {
795 if (user->supported_styles[i] ==
796 xim->supported_styles[j]) {
797 return user->supported_styles[i];
801 return DEFAULTStyle; /* Default Style */
804 /* These lisp-callable functions will be sealed until xim-leim is needed.
805 Oct 22 1999 - kazz */
808 * External callable function for XIM
810 DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /*
811 Open the XIC on the frame if XIM is available.
812 Commonly, use this as \(x-open-xim \(selected-frame)).
813 If the frame is not on X device, return signal.
814 If XIC is created successfully return t. If not return nil.
820 CHECK_LIVE_FRAME (frame);
822 if (!FRAME_X_P (f)) {
823 return signal_simple_error(
824 "This frame is not on X device", frame);
827 return FRAME_X_XIC (f) ? Qt : Qnil;
830 DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /*
831 Close the XIC on the frame if it exists.
832 Commonly, use this as \(x-close-xim \(selected-frame)).
833 If the frame is not on X device, return signal.
834 Otherwise, it destroys the XIC if it exists, then returns t anyway.
841 CHECK_LIVE_FRAME (frame);
843 if (!FRAME_X_P (f)) {
844 return signal_simple_error(
845 "This frame is not on X device", frame);
847 d = XDEVICE (FRAME_DEVICE (f));
848 if (DEVICE_X_XIM (d)) {
849 /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */
850 FRAME_X_XIC (XFRAME (f)) = NULL;
857 syms_of_input_method_xlib (void)
859 defsymbol (&Qxim_xlib, "xim-xlib");
860 #if 0 /* see above */
861 DEFSUBR (Fx_open_xim);
862 DEFSUBR (Fx_close_xim);
867 vars_of_input_method_xlib (void)
869 Fprovide (intern ("xim"));
873 /* ====================================================================== */
874 /* Internal Debugging Routines */
875 /* ====================================================================== */
879 describe_XIM (XIM xim)
883 /* Print locale of XIM */
884 stderr_out ("\nXIM Locale of IM: %s\n", XLocaleOfIM(xim));
886 /* List supported input method styles */
887 XGetIMValues(xim, XNQueryInputStyle, &styles, NULL);
889 stderr_out ("\n%d input style(s) supported by input method.\n",
890 styles->count_styles);
893 for (int i=0; i < styles->count_styles; i++) {
894 describe_XIMStyle (styles->supported_styles[i]);
896 #endif /* DEBUG_XIM */
901 describe_XFontSet (XFontSet fontset)
903 XFontStruct **font_struct_list;
904 char **font_name_list;
907 if (fontset == NULL) {
908 stderr_out ("NULL\n");
912 count = XFontsOfFontSet(fontset, &font_struct_list, &font_name_list);
913 stderr_out ( "%d font(s) available:\n", count);
914 for (i=0 ; i < count ; i++) {
915 stderr_out ("Font: %s\n", *(font_name_list+i));
920 describe_Status (Status status)
922 #define DESCRIBE_STATUS(value) \
923 if (status == value) { \
924 stderr_out ("Status: " #value "\n"); \
927 DESCRIBE_STATUS (XBufferOverflow);
928 DESCRIBE_STATUS (XLookupNone);
929 DESCRIBE_STATUS (XLookupKeySym);
930 DESCRIBE_STATUS (XLookupBoth);
931 DESCRIBE_STATUS (XLookupChars);
932 #undef DESCRIBE_STATUS
936 describe_Window (Window win)
939 sprintf (xwincmd, "xwininfo -id 0x%x >&2; xwininfo -events -id 0x%x >&2",
940 (int) win, (int) win);
945 describe_XIC (XIC xic)
948 Window client_win=0, focus_win=0;
949 char *resourceName = NULL;
950 char *resourceClass = NULL;
951 char *bad_arg = NULL;
952 unsigned long filter_mask = NoEventMask;
953 XVaNestedList p_list, s_list;
954 XFontSet p_fontset = NULL, s_fontset = NULL;
955 Pixel p_fg=0, p_bg = 0, s_fg=0, s_bg = 0;
956 XRectangle *p_area = NULL, *s_area = NULL;
957 XRectangle *p_needed = NULL, *s_needed = NULL;
958 XPoint *p_spot = NULL;
960 /* Check for valid input context and method */
962 stderr_out ("Input method is NULL\n");
965 stderr_out ("XIMOfIC() returns NULL\n");
967 /* Print out Input Context Attributes */
968 p_list = XVaCreateNestedList (0,
969 XNFontSet, &p_fontset,
971 XNAreaNeeded, &p_needed,
972 XNSpotLocation, &p_spot,
977 s_list = XVaCreateNestedList (0,
978 XNFontSet, &s_fontset,
980 XNAreaNeeded, &s_needed,
985 bad_arg = XGetICValues(xic,
986 XNInputStyle, &style,
987 XNFilterEvents, &filter_mask,
988 XNClientWindow, &client_win,
989 XNFocusWindow, &focus_win,
990 XNResourceName, &resourceName,
991 XNResourceClass, &resourceClass,
992 XNPreeditAttributes, p_list,
993 XNStatusAttributes, s_list,
998 if (bad_arg != NULL) {
999 stderr_out ("Couldn't get IC value: %s\n", bad_arg);
1001 stderr_out ("\nInput method context attributes:\n");
1002 stderr_out ("Style: "); describe_XIMStyle (style);
1003 stderr_out ("Client window: %lx\n", (unsigned long int)client_win);
1004 stderr_out ("Focus window: %lx\n", (unsigned long int)focus_win);
1005 stderr_out ("Preedit:\n");
1006 describe_XRectangle (" Area", p_area);
1007 describe_XRectangle (" Area needed", p_needed);
1008 stderr_out (" foreground: %lx\n", (unsigned long int)p_fg);
1009 stderr_out (" background: %lx\n", (unsigned long int)p_bg);
1010 stderr_out (" fontset: "); describe_XFontSet (p_fontset);
1011 stderr_out ("Status:\n");
1012 describe_XRectangle (" Area", s_area);
1013 describe_XRectangle (" Area needed", s_needed);
1014 stderr_out (" foreground: %lx\n", (unsigned long int)s_fg);
1015 stderr_out (" background: %lx\n", (unsigned long int)s_bg);
1016 stderr_out (" fontset: \n"); describe_XFontSet (s_fontset);
1017 stderr_out ("XNResourceName: %s\n", resourceName
1018 ? resourceName : "NULL");
1019 stderr_out ("XNResourceClass: %s\n", resourceClass
1020 ? resourceClass : "NULL");
1021 stderr_out ("XNFilterEvents: "); describe_event_mask (filter_mask);
1025 describe_XRectangle (char *name, XRectangle *r)
1028 stderr_out ("%s: NULL\n", name);
1030 stderr_out ("%s: x=%d y=%d w=%d h=%d\n",
1031 name, r->x, r->y, r->width, r->height);
1035 /* Print out elements of Event mask */
1036 /* Defines from X11/X.h */
1038 describe_event_mask (unsigned long mask)
1040 #define DESCRIBE_EVENT_MASK(bit) if ((bit) & mask) stderr_out (#bit " ")
1041 DESCRIBE_EVENT_MASK (NoEventMask);
1042 DESCRIBE_EVENT_MASK (KeyPressMask);
1043 DESCRIBE_EVENT_MASK (KeyReleaseMask);
1044 DESCRIBE_EVENT_MASK (ButtonPressMask);
1045 DESCRIBE_EVENT_MASK (ButtonReleaseMask);
1046 DESCRIBE_EVENT_MASK (EnterWindowMask);
1047 DESCRIBE_EVENT_MASK (LeaveWindowMask);
1048 DESCRIBE_EVENT_MASK (PointerMotionMask);
1049 DESCRIBE_EVENT_MASK (PointerMotionHintMask);
1050 DESCRIBE_EVENT_MASK (Button1MotionMask);
1051 DESCRIBE_EVENT_MASK (Button2MotionMask);
1052 DESCRIBE_EVENT_MASK (Button3MotionMask);
1053 DESCRIBE_EVENT_MASK (Button4MotionMask);
1054 DESCRIBE_EVENT_MASK (Button5MotionMask);
1055 DESCRIBE_EVENT_MASK (ButtonMotionMask);
1056 DESCRIBE_EVENT_MASK (KeymapStateMask);
1057 DESCRIBE_EVENT_MASK (ExposureMask);
1058 DESCRIBE_EVENT_MASK (VisibilityChangeMask);
1059 DESCRIBE_EVENT_MASK (StructureNotifyMask);
1060 DESCRIBE_EVENT_MASK (ResizeRedirectMask);
1061 DESCRIBE_EVENT_MASK (SubstructureNotifyMask);
1062 DESCRIBE_EVENT_MASK (SubstructureRedirectMask);
1063 DESCRIBE_EVENT_MASK (FocusChangeMask);
1064 DESCRIBE_EVENT_MASK (PropertyChangeMask);
1065 DESCRIBE_EVENT_MASK (ColormapChangeMask);
1066 DESCRIBE_EVENT_MASK (OwnerGrabButtonMask);
1067 #undef DESCRIBE_EVENT_MASK
1072 describe_XIMStyle (XIMStyle style)
1074 #define DESCRIBE_STYLE(bit) \
1075 if (bit & style) { \
1076 stderr_out (#bit " "); \
1079 DESCRIBE_STYLE (XIMPreeditArea);
1080 DESCRIBE_STYLE (XIMPreeditCallbacks);
1081 DESCRIBE_STYLE (XIMPreeditPosition);
1082 DESCRIBE_STYLE (XIMPreeditNothing);
1083 DESCRIBE_STYLE (XIMPreeditNone);
1084 DESCRIBE_STYLE (XIMStatusArea);
1085 DESCRIBE_STYLE (XIMStatusCallbacks);
1086 DESCRIBE_STYLE (XIMStatusNothing);
1087 DESCRIBE_STYLE (XIMStatusNone);
1088 #undef DESCRIBE_STYLE
1093 describe_XIMStyles (XIMStyles *p)
1096 stderr_out ("%d Style(s):\n", p->count_styles);
1097 for (i=0; i<p->count_styles ; i++) {
1098 describe_XIMStyle (p->supported_styles[i]);
1102 #endif /* DEBUG_SXEMACS */
1104 /* Random cruft follows */
1108 Unit_Test (struct frame *f, char * s)
1109 /* mrb unit testing */
1111 XrmValue fromVal, toVal;
1114 fromVal.size = strlen (s);
1115 toVal.addr = (XtPointer) &user_preferred_XIMStyles;
1116 toVal.size = sizeof (XIMStyles);
1118 if (XtConvertAndStore (FRAME_X_TEXT_WIDGET (f), XtRString, &fromVal,
1119 XtRXimStyles, &toVal) != False) {
1120 stderr_out ("Unit_Test: fromVal.addr=0x%x\n",fromVal.addr);
1121 stderr_out ("Unit_Test: fromVal.size=%d\n", fromVal.size);
1122 stderr_out ("Unit_Test: toVal.addr=0x%x\n", toVal.addr);
1123 stderr_out ("Unit_Test: toVal.size=%d\n", toVal.size);
1124 describe_XIMStyles ((XIMStyles *) toVal.addr);
1128 #endif /* XIM_XLIB only */
1131 /* Get a fontset for IM to use */
1133 x_init_fontset (struct device *d)
1135 Display *dpy = DEVICE_X_DISPLAY (d);
1137 char ** missing_charsets;
1138 int num_missing_charsets;
1139 char * default_string;
1140 /* char * font_set_string = "-dt-interface user-medium-r-normal\
1141 -s*-*-*-*-*-*-*-*-*";*/
1142 char *font_set_string =
1143 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*,"
1144 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0,"
1145 "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,"
1146 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0";
1148 DEVICE_X_FONTSET (d) = fontset =
1149 XCreateFontSet (dpy, font_set_string,
1151 &num_missing_charsets,
1154 if (fontset == NULL) {
1155 stderr_out("Unable to create fontset from string:\n%s\n",
1159 if (num_missing_charsets > 0) {
1161 stderr_out ("\nMissing charsets for fontset %s:\n",
1163 for (i=0; i < num_missing_charsets; i++) {
1164 stderr_out ("%s\n", missing_charsets[i]);
1166 XFreeStringList (missing_charsets);
1167 stderr_out ("Default string: %s\n", default_string);
1171 describe_XFontSet (fontset);