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_warn2(fmt, str1, str2) \
91 warn_when_safe (Qxim_xlib, Qwarning, fmt, str1, str2)
92 #define xim_info(str) warn_when_safe (Qxim_xlib, Qinfo, str)
94 #ifdef XIM_XLIB /* XIM_XLIB specific */
95 /* Get/Set IC values for just one attribute */
97 #define XIC_Value(Get_Set, xic, name, attr, value) \
100 XVaNestedList list = XVaCreateNestedList( \
101 0, attr, value, NULL); \
102 if ((bad_arg = X##Get_Set##ICValues( \
103 xic, name, list, NULL)) != NULL) \
104 stderr_out ("X" #Get_Set "ICValues " \
105 "bad Arg: %s\n", bad_arg); \
108 #else /* ! DEBUG_SXEMACS */
109 #define XIC_Value(Get_Set, xic, name, attr, value) \
111 XVaNestedList list = XVaCreateNestedList( \
112 0, attr, value, NULL); \
113 X##Get_Set##ICValues (xic, name, list, NULL); \
116 #endif /* DEBUG_SXEMACS */
118 static char DefaultXIMStyles[] =
119 "XIMPreeditPosition|XIMStatusArea\n"
120 "XIMPreeditPosition|XIMStatusNone\n"
121 "XIMPreeditPosition|XIMStatusNothing\n"
122 "XIMPreeditNothing|XIMStatusArea\n"
123 "XIMPreeditNothing|XIMStatusNothing\n"
124 "XIMPreeditNothing|XIMStatusNone\n"
125 "XIMPreeditNone|XIMStatusArea\n"
126 "XIMPreeditNone|XIMStatusNothing\n"
127 "XIMPreeditNone|XIMStatusNone";
129 static XIMStyle best_style (XIMStyles *user, XIMStyles *xim);
130 #endif /* XIM_XLIB only */
132 /* This function is documented, but no prototype in the header files */
133 EXTERN_C char * XSetIMValues(XIM, ...);
136 Initialize_Locale (void)
140 /* dverna - Nov. 98: #### DON'T DO THIS !!! The default XtLanguageProc
141 routine calls setlocale(LC_ALL, lang) which fucks up our lower-level
142 locale management, and especially the value of LC_NUMERIC. Anyway,
143 since at this point, we don't know yet whether we're gonna need an
144 X11 frame, we should really do it manually and not use Xlib's dumb
146 /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/
147 if ((locale = setlocale (LC_ALL, "")) == NULL) {
148 xim_warn ("Can't set locale.\n"
149 "Using C locale instead.\n");
152 if ((locale = setlocale (LC_ALL, "C")) == NULL) {
153 xim_warn ("Can't even set locale to `C'!\n");
158 if (!XSupportsLocale ()) {
159 xim_warn1 ("X Windows does not support locale `%s'\n"
160 "Using C Locale instead\n", locale);
163 if (setlocale (LC_ALL, "C") == NULL) {
164 xim_warn ("Can't set locale to `C'!\n");
167 if (!XSupportsLocale ()) {
168 xim_warn ("X Windows does not support locale `C'!\n");
173 setlocale(LC_NUMERIC, "C");
175 if (XSetLocaleModifiers ("") == NULL) {
176 xim_warn ("XSetLocaleModifiers(\"\") failed\n"
177 "Check the value of the XMODIFIERS "
178 "environment variable.\n");
182 #ifdef XIM_XLIB /* starting XIM specific codes */
184 /* Callbacks for IM are supported from X11R6 or later. */
185 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK
187 static Boolean xim_initted = False;
189 /* Called from when XIM is destroying.
190 Clear all the XIC when the XIM was destroying... */
192 IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data)
194 struct device *d = (struct device *)client_data;
197 DEVICE_FRAME_LOOP (tail, d) {
198 struct frame *target_frame = XFRAME (XCAR (tail));
199 if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame)) {
200 /* XDestroyIC (FRAME_X_XIC (target_frame)); */
201 FRAME_X_XIC (target_frame) = NULL;
205 DEVICE_X_XIM (d) = NULL;
210 /* This is registered in XIM_init_device (when DEVICE is initializing).
211 This activates XIM when XIM becomes available. */
213 IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
215 struct device *d = (struct device *)client_data;
218 XIMCallback ximcallback;
221 /* if no xim is presented, initialize xim ... */
222 if ( xim_initted == False ) {
224 XtGetApplicationNameAndClass (dpy, &name, &class);
225 DEVICE_X_XIM (d) = xim =
226 XOpenIM (dpy, XtDatabase (dpy), name, class);
228 /* destroy callback for im */
229 ximcallback.callback = (XIMProc) IMDestroyCallback;
230 ximcallback.client_data = (XPointer) d;
231 XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
234 /* activate XIC on all the X frames... */
235 DEVICE_FRAME_LOOP (tail, d) {
236 struct frame *target_frame = XFRAME (XCAR (tail));
237 if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame)) {
238 XIM_init_frame (target_frame);
243 #endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
245 /* Initialize XIM for X device.
246 Register the use of XIM using XRegisterIMInstantiateCallback. */
248 XIM_init_device (struct device *d)
250 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK /* X11R6+ */
251 DEVICE_X_XIM (d) = NULL;
252 XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL,
253 #ifdef XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE
254 /* The sixth parameter is of type
255 XPointer in XFree86 but (XPointer *)
256 on most other X11's. */
257 (XIDProc) IMInstantiateCallback,
259 #else /* X Consortium prototype */
260 (XIMProc) IMInstantiateCallback,
262 #endif /* XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE */
265 #else /* pre-X11R6 */
266 Display *dpy = DEVICE_X_DISPLAY (d);
270 XtGetApplicationNameAndClass (dpy, &name, &class);
271 DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class);
273 xim_warn ("XOpenIM() failed...no input server available\n");
276 XGetIMValues (xim, XNQueryInputStyle,
277 &DEVICE_X_XIM_STYLES (d), NULL);
280 #endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
288 /* Callback for the deleting frame. */
290 XIM_delete_frame (Widget w, XtPointer client_data, XtPointer call_data)
292 struct frame *f = (struct frame *) client_data;
293 struct device *d = XDEVICE (FRAME_DEVICE (f));
295 if (DEVICE_X_XIM (d)) {
296 if (FRAME_X_XIC (f)) {
297 XDestroyIC (FRAME_X_XIC (f));
298 FRAME_X_XIC (f) = NULL;
304 /* Initialize XIC for new frame.
305 Create an X input context (XIC) for this frame. */
307 XIM_init_frame (struct frame *f)
309 struct device *d = XDEVICE (FRAME_DEVICE (f));
311 Widget w = FRAME_X_TEXT_WIDGET (f);
312 Window win = XtWindow (w);
313 XRectangle p_area = {0,0,1,1}, s_area = {0,0,1,1};
316 XVaNestedList p_list, s_list;
328 #define res(name, class, representation, field, default_value) \
329 { name, class, representation, sizeof(xic_vars.field), \
330 XtOffsetOf(xic_vars_t, field), XtRString, \
333 static XtResource resources[] =
335 /* name class represent'n field default value */
336 res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, (XtPointer) DefaultXIMStyles),
337 res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, (XtPointer) XtDefaultFontSet),
338 res(XtNximForeground, XtCForeground, XtRPixel, fg, (XtPointer) XtDefaultForeground),
339 res(XtNximBackground, XtCBackground, XtRPixel, bg, (XtPointer) XtDefaultBackground)
343 xim = DEVICE_X_XIM (d);
349 w = FRAME_X_TEXT_WIDGET (f);
354 if (FRAME_X_XIC (f)) {
357 XtGetApplicationResources (w, &xic_vars,
358 resources, XtNumber (resources),
360 if (!xic_vars.fontset) {
361 xim_warn ("Can't get fontset resource for Input Method\n");
362 FRAME_X_XIC (f) = NULL;
367 XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES(d), NULL);
368 FRAME_X_XIC_STYLE (f) = style =
369 best_style (&xic_vars.styles,
370 (XIMStyles *)DEVICE_X_XIM_STYLES(d));
372 p_list = XVaCreateNestedList (0,
374 XNSpotLocation, &spot,
375 XNForeground, xic_vars.fg,
376 XNBackground, xic_vars.bg,
377 XNFontSet, xic_vars.fontset,
380 if (style & XIMStatusArea) {
381 s_list = XVaCreateNestedList (0,
383 XNForeground, xic_vars.fg,
384 XNBackground, xic_vars.bg,
385 XNFontSet, xic_vars.fontset,
387 FRAME_X_XIC (f) = xic =
392 XNPreeditAttributes, p_list,
393 XNStatusAttributes, s_list,
397 FRAME_X_XIC (f) = xic =
402 XNPreeditAttributes, p_list,
408 char *lang = getenv("LANG");
409 char *xmodifiers = getenv("XMODIFIERS");
410 xim_warn2 ("Warning: XCreateIC failed. LANG='%s' XMODIFIERS='%s'\n",
411 (lang?lang:""), (xmodifiers?xmodifiers:""));
415 if (style & XIMPreeditPosition) {
416 XPoint *frame_spot = &(FRAME_X_XIC_SPOT(f));
417 frame_spot->x = frame_spot->y = -1;
424 #ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK
425 /* when frame is going to be destroyed (closed) */
426 XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback,
427 XIM_delete_frame, (XtPointer)f);
433 XIM_SetGeometry (struct frame *f)
442 xic = FRAME_X_XIC (f);
447 style = FRAME_X_XIC_STYLE (f);
449 if (style & XIMStatusArea) {
450 /* Place Status Area in bottom right corner */
451 /* Negotiate geometry of status area */
452 /* See O'Reilly Xlib XIM chapter (but beware, it's buggy) */
455 /* If input method has existing status area, use its current
457 /* The following at least works for Sun's htt */
458 area.x = area.y = area.width = area.height = 0;
459 XIC_Value (Set, xic, XNStatusAttributes, XNAreaNeeded, &area);
460 XIC_Value (Get, xic, XNStatusAttributes, XNAreaNeeded, &needed);
461 if (needed->width == 0) {
462 /* Use XNArea instead of XNAreaNeeded */
463 XIC_Value (Get, xic, XNStatusAttributes,
466 area.width = needed->width;
467 area.height = needed->height;
468 area.x = FRAME_RIGHT_BORDER_START (f) - area.width;
469 area.y = FRAME_BOTTOM_BORDER_START (f) - area.height;
472 stderr_out ("Putting StatusArea in x=%d y=%d w=%d h=%d\n",
473 area.x, area.y, area.width, area.height);
474 #endif /* DEBUG_XIM */
476 XIC_Value (Set, xic, XNStatusAttributes, XNArea, &area);
479 if (style & XIMPreeditPosition) {
480 /* Set Preedit Area to whole frame size (sans border) */
481 /* We include the border because Preedit window might be larger
482 than display line at edge. #### FIX: we should adjust to make
483 sure that there is always room for the spot sub-window */
484 area.x = FRAME_LEFT_BORDER_START (f);
485 area.y = FRAME_TOP_BORDER_START (f);
486 area.width = FRAME_RIGHT_BORDER_END (f) - area.x;
487 area.height = FRAME_BOTTOM_BORDER_END (f) - area.y;
488 XIC_Value(Set, xic, XNPreeditAttributes, XNArea, &area);
497 XIM_SetSpotLocation (struct frame *f, int x, int y)
499 XIC xic = FRAME_X_XIC (f);
500 XPoint *spot = &(FRAME_X_XIC_SPOT (f));
502 /* Only care if we have a valid XIC using Over the Spot in
503 * a different location */
505 !(FRAME_X_XIC_STYLE (f) & XIMPreeditPosition) ||
506 (spot->x == (short) x &&
507 spot->y == (short) y)) {
513 /* #### FIX: Must make sure spot fits within Preedit Area */
514 XIC_Value (Set, xic, XNPreeditAttributes, XNSpotLocation, spot);
516 stderr_out ("Spot: %d %d\n", spot->x, spot->y);
521 XIM_focus_event (struct frame *f, int in_p)
523 if (FRAME_X_XIC (f) /* && FRAME_X_XIM_REGISTERED(f) */) {
524 (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f));
529 #define XIM_Composed_Text_BUFSIZE 64
530 typedef struct XIM_Composed_Text
533 wchar_t data [XIM_Composed_Text_BUFSIZE];
536 static XIM_Composed_Text composed_input_buf = {XIM_Composed_Text_BUFSIZE, {0}};
539 /* get_XIM_input -- Process results of input method composition.
541 This function copies the results of the input method composition to
542 composed_input_buf. Then for each character, a custom event of type
543 wc_atom is sent with the character as its data.
545 It is probably more efficient to copy the composition results to some
546 allocated memory and send a single event pointing to that memory.
547 That would cut down on the event processing as well as allow quick
548 insertion into the buffer of the whole string. It might require some
549 care, though, to avoid fragmenting memory through the allocation and
550 freeing of many small chunks. Maybe the existing system for
551 (single-byte) string allocation can be used, multiplying the length by
552 sizeof (wchar_t) to get the right size. */
555 get_XIM_input (XKeyPressedEvent *x_key_event, XIC ic, Display *dpy)
561 XClientMessageEvent new_event;
564 len = XwcLookupString (ic, x_key_event, composed_input_buf.data,
565 composed_input_buf.size, &keysym, &status);
567 case XBufferOverflow:
568 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
576 new_event.type = ClientMessage;
577 new_event.display = x_key_event->display;
578 new_event.window = x_key_event->window;
579 new_event.message_type = wc_atom;
580 new_event.format = 32; /* 32-bit wide data */
581 new_event.data.l[2] = new_event.data.l[3] = new_event.data.l[4] = 0L;
582 new_event.data.l[0] = x_key_event->time;
583 for (i = 0; i < len; i++) {
584 new_event.data.l[1] = ((wchar_t *) composed_input_buf.data)[i];
585 XSendEvent (display, main_window, False, 0L,
586 (XEvent *) &new_event);
591 /* ============================================================== */
592 /* X input method style determination */
593 /* ============================================================== */
596 #define done(type, value) \
597 if (toVal->addr != NULL) { \
598 if (toVal->size < sizeof(type)) { \
599 toVal->size = sizeof(type); \
602 *(type*)toVal->addr = (value); \
604 static type static_val; \
605 static_val = (value); \
606 toVal->addr = (XPointer)&static_val; \
608 toVal->size = sizeof(type); \
609 return True /* Caller supplies `;' */
613 * This is a standard Xt type converter, except that the caller MUST
614 * supply a proper non-NULL toVal XIMStyles structure that we will
617 * fromVal points to a string like
619 "XIMPreeditPosition|XIMStatusArea,
620 XIMPreeditPosition|XIMStatusNothing
621 XIMPreeditNothing|XIMStatusNothing"
623 * This is converted in the obvious way to a XIMStyles structure.
625 * mrb: #### Fix this to handle Motif-style specifications for
626 * XIMStyles as well: overTheSpot, rootWindow, none */
628 /* XtTypeConverter */
630 EmacsXtCvtStringToXIMStyles (
636 XtPointer *converter_data)
638 #define STYLE_INFO(style) { style, #style, sizeof(#style) }
639 static struct XIMStyleInfo {
640 const XIMStyle style;
641 const char * const name;
643 } emacs_XIMStyleInfo[] = {
644 STYLE_INFO (XIMPreeditPosition|XIMStatusArea),
645 STYLE_INFO (XIMPreeditPosition|XIMStatusNothing),
646 STYLE_INFO (XIMPreeditPosition|XIMStatusNone),
647 STYLE_INFO (XIMPreeditNothing|XIMStatusArea),
648 STYLE_INFO (XIMPreeditNothing|XIMStatusNothing),
649 STYLE_INFO (XIMPreeditNothing|XIMStatusNone),
650 STYLE_INFO (XIMPreeditNone|XIMStatusArea),
651 STYLE_INFO (XIMPreeditNone|XIMStatusNothing),
652 STYLE_INFO (XIMPreeditNone|XIMStatusNone)
656 char *s = (char *) fromVal->addr;
657 char *end = s + fromVal->size;
658 XIMStyles * const p = (XIMStyles *) toVal->addr;
659 const char * const delimiter = " \t\n\r:;," ;
660 const int max_styles = XtNumber(emacs_XIMStyleInfo);
665 stderr_out ("EmacsCvtStringToXIMStyles called with "
666 "size=%d, string=\"%s\"\n",
667 fromVal->size, (char *) fromVal->addr);
668 #endif /* DEBUG_XIM */
670 if (*num_args != 0) {
671 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
672 XtAppWarningMsg(the_app_con, "wrongParameters",
673 "cvtStringToXIMStyle",
675 "String to XIMStyle conversion requires "
676 "exactly 0 parameters",
677 (String *)NULL, (Cardinal *)NULL);
682 /* Make sure caller is giving us good data */
683 assert (fromVal->addr != NULL);
684 assert (fromVal->size == strlen(fromVal->addr)+1);
685 assert (toVal->addr != NULL);
686 assert (toVal->size == sizeof(XIMStyles));
687 #endif /* DEBUG_SXEMACS */
690 p->supported_styles = xnew_atomic_array(XIMStyle, max_styles);
693 * The following routine assumes that the style name resource is
694 * identical with the programmatic name of style. For example,
695 * "XIMPreeditPosition|XIMStatusArea" means the
696 * XIMPreeditPosition|XIMStatusArea value is specified. If the
697 * style name is changed, such as "OverTheSpot|imDisplaysInClient",
698 * the parsing logic below should be modified as well. */
700 if ((c = strtok(s, delimiter)) == NULL) {
704 for(i=0 ; i<max_styles ; i++) {
705 struct XIMStyleInfo *rec = emacs_XIMStyleInfo + i;
706 if(!strncmp(c, rec->name, rec->namelen - 1)) {
707 p->supported_styles[p->count_styles] =
713 if((c = strtok(NULL, delimiter)) == NULL) {
718 if (p->count_styles == 0) {
719 /* No valid styles? */
720 char buf[strlen(fromVal->addr) +
721 strlen(DefaultXIMStyles) +
725 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
727 len = snprintf(buf, sizeof(buf),
728 "Cannot convert string \"%s\" to type XIMStyles.\n"
729 "Using default string \"%s\" instead.\n",
730 fromVal->addr, DefaultXIMStyles);
731 assert(len >= 0 && (size_t)len < sizeof(buf));
732 XtAppWarningMsg(the_app_con, "wrongParameters",
733 "cvtStringToXIMStyle",
735 buf, (String *)NULL, (Cardinal *)NULL);
736 new_from.addr = DefaultXIMStyles;
737 new_from.size = sizeof(DefaultXIMStyles);
738 return EmacsXtCvtStringToXIMStyles (dpy, args, num_args,
742 XREALLOC_ARRAY (p->supported_styles, XIMStyle, p->count_styles);
743 *converter_data = (char *) True;
752 XtPointer converter_data,
757 stderr_out ("Converter data: %x\n", converter_data);
758 stderr_out ("EmacsFreeXIMStyles called\n");
759 #endif /* DEBUG_XIM */
761 if (*num_args != 0) {
762 XtAppWarningMsg(app, "wrongParameters", "freeXIMStyles",
764 "Freeing an XIMStyles requires that "
765 "zero arguments be passwd",
766 (String *)NULL, (Cardinal *)NULL);
770 if (converter_data) {
771 Boolean free_p = (Boolean) (EMACS_INT)converter_data;
772 XIMStyles *free_me = (XIMStyles *) toVal->addr;
774 /* use our free function */
775 xfree(free_me->supported_styles);
781 /* O'Reilly XLib Programming Manual, pg. 371 */
782 /* Much nicer implementation than O'Reilly */
783 /* Choose the more `complicated', hence nicer, XIM input style */
785 BetterStyle (XIMStyle s, XIMStyle t)
787 #define CHECK_XIMStyle_BIT(bit) \
788 if ((s ^ t) & bit) { return (s & bit) ? s : t; }
790 CHECK_XIMStyle_BIT (XIMPreeditCallbacks);
791 CHECK_XIMStyle_BIT (XIMPreeditPosition);
792 CHECK_XIMStyle_BIT (XIMPreeditArea);
793 CHECK_XIMStyle_BIT (XIMPreeditNothing);
794 CHECK_XIMStyle_BIT (XIMStatusCallbacks);
795 CHECK_XIMStyle_BIT (XIMStatusArea);
796 CHECK_XIMStyle_BIT (XIMStatusNothing);
797 #undef CHECK_XIMStyle_BIT
802 /* Choose the best style, given:
803 * - user preferences (already checked to be supported by SXEmacs)
804 * - styles supported by the input method */
805 #define DEFAULTStyle (XIMPreeditNothing|XIMStatusNothing)
807 best_style (XIMStyles *user, XIMStyles *xim)
810 for (i=0 ; i<user->count_styles ; i++) {
811 for (j=0 ; j<xim->count_styles ; j++) {
812 if (user->supported_styles[i] ==
813 xim->supported_styles[j]) {
814 return user->supported_styles[i];
818 return DEFAULTStyle; /* Default Style */
821 /* These lisp-callable functions will be sealed until xim-leim is needed.
822 Oct 22 1999 - kazz */
825 * External callable function for XIM
827 DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /*
828 Open the XIC on the frame if XIM is available.
829 Commonly, use this as \(x-open-xim \(selected-frame)).
830 If the frame is not on X device, return signal.
831 If XIC is created successfully return t. If not return nil.
837 CHECK_LIVE_FRAME (frame);
839 if (!FRAME_X_P (f)) {
840 return signal_simple_error(
841 "This frame is not on X device", frame);
844 return FRAME_X_XIC (f) ? Qt : Qnil;
847 DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /*
848 Close the XIC on the frame if it exists.
849 Commonly, use this as \(x-close-xim \(selected-frame)).
850 If the frame is not on X device, return signal.
851 Otherwise, it destroys the XIC if it exists, then returns t anyway.
858 CHECK_LIVE_FRAME (frame);
860 if (!FRAME_X_P (f)) {
861 return signal_simple_error(
862 "This frame is not on X device", frame);
864 d = XDEVICE (FRAME_DEVICE (f));
865 if (DEVICE_X_XIM (d)) {
866 /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */
867 FRAME_X_XIC (XFRAME (f)) = NULL;
874 syms_of_input_method_xlib (void)
876 defsymbol (&Qxim_xlib, "xim-xlib");
877 #if 0 /* see above */
878 DEFSUBR (Fx_open_xim);
879 DEFSUBR (Fx_close_xim);
884 vars_of_input_method_xlib (void)
886 Fprovide (intern ("xim"));
890 /* ====================================================================== */
891 /* Internal Debugging Routines */
892 /* ====================================================================== */
896 describe_XIM (XIM xim)
900 /* Print locale of XIM */
901 stderr_out ("\nXIM Locale of IM: %s\n", XLocaleOfIM(xim));
903 /* List supported input method styles */
904 XGetIMValues(xim, XNQueryInputStyle, &styles, NULL);
906 stderr_out ("\n%d input style(s) supported by input method.\n",
907 styles->count_styles);
910 for (int i=0; i < styles->count_styles; i++) {
911 describe_XIMStyle (styles->supported_styles[i]);
913 #endif /* DEBUG_XIM */
918 describe_XFontSet (XFontSet fontset)
920 XFontStruct **font_struct_list;
921 char **font_name_list;
924 if (fontset == NULL) {
925 stderr_out ("NULL\n");
929 count = XFontsOfFontSet(fontset, &font_struct_list, &font_name_list);
930 stderr_out ( "%d font(s) available:\n", count);
931 for (i=0 ; i < count ; i++) {
932 stderr_out ("Font: %s\n", *(font_name_list+i));
937 describe_Status (Status status)
939 #define DESCRIBE_STATUS(value) \
940 if (status == value) { \
941 stderr_out ("Status: " #value "\n"); \
944 DESCRIBE_STATUS (XBufferOverflow);
945 DESCRIBE_STATUS (XLookupNone);
946 DESCRIBE_STATUS (XLookupKeySym);
947 DESCRIBE_STATUS (XLookupBoth);
948 DESCRIBE_STATUS (XLookupChars);
949 #undef DESCRIBE_STATUS
953 describe_Window (Window win)
956 int sz = snprintf (xwincmd, sizeof(xwincmd),
957 "xwininfo -id 0x%x >&2; xwininfo -events -id 0x%x >&2",
958 (int) win, (int) win);
959 if ( sz >= 0 && (size_t) sz < sizeof(xwincmd) ) {
960 int exit_code = system (xwincmd);
961 if ( exit_code != 0 )
962 stderr_out("command '%s' failed with exit code %d",
965 stderr_out("Could not generate wininfo command line");
969 describe_XIC (XIC xic)
972 Window client_win=0, focus_win=0;
973 char *resourceName = NULL;
974 char *resourceClass = NULL;
975 char *bad_arg = NULL;
976 unsigned long filter_mask = NoEventMask;
977 XVaNestedList p_list, s_list;
978 XFontSet p_fontset = NULL, s_fontset = NULL;
979 Pixel p_fg=0, p_bg = 0, s_fg=0, s_bg = 0;
980 XRectangle *p_area = NULL, *s_area = NULL;
981 XRectangle *p_needed = NULL, *s_needed = NULL;
982 XPoint *p_spot = NULL;
984 /* Check for valid input context and method */
986 stderr_out ("Input method is NULL\n");
989 stderr_out ("XIMOfIC() returns NULL\n");
991 /* Print out Input Context Attributes */
992 p_list = XVaCreateNestedList (0,
993 XNFontSet, &p_fontset,
995 XNAreaNeeded, &p_needed,
996 XNSpotLocation, &p_spot,
1001 s_list = XVaCreateNestedList (0,
1002 XNFontSet, &s_fontset,
1004 XNAreaNeeded, &s_needed,
1005 XNForeground, &s_fg,
1006 XNBackground, &s_bg,
1009 bad_arg = XGetICValues(xic,
1010 XNInputStyle, &style,
1011 XNFilterEvents, &filter_mask,
1012 XNClientWindow, &client_win,
1013 XNFocusWindow, &focus_win,
1014 XNResourceName, &resourceName,
1015 XNResourceClass, &resourceClass,
1016 XNPreeditAttributes, p_list,
1017 XNStatusAttributes, s_list,
1022 if (bad_arg != NULL) {
1023 stderr_out ("Couldn't get IC value: %s\n", bad_arg);
1025 stderr_out ("\nInput method context attributes:\n");
1026 stderr_out ("Style: "); describe_XIMStyle (style);
1027 stderr_out ("Client window: %lx\n", (unsigned long int)client_win);
1028 stderr_out ("Focus window: %lx\n", (unsigned long int)focus_win);
1029 stderr_out ("Preedit:\n");
1030 describe_XRectangle (" Area", p_area);
1031 describe_XRectangle (" Area needed", p_needed);
1032 stderr_out (" foreground: %lx\n", (unsigned long int)p_fg);
1033 stderr_out (" background: %lx\n", (unsigned long int)p_bg);
1034 stderr_out (" fontset: "); describe_XFontSet (p_fontset);
1035 stderr_out ("Status:\n");
1036 describe_XRectangle (" Area", s_area);
1037 describe_XRectangle (" Area needed", s_needed);
1038 stderr_out (" foreground: %lx\n", (unsigned long int)s_fg);
1039 stderr_out (" background: %lx\n", (unsigned long int)s_bg);
1040 stderr_out (" fontset: \n"); describe_XFontSet (s_fontset);
1041 stderr_out ("XNResourceName: %s\n", resourceName
1042 ? resourceName : "NULL");
1043 stderr_out ("XNResourceClass: %s\n", resourceClass
1044 ? resourceClass : "NULL");
1045 stderr_out ("XNFilterEvents: "); describe_event_mask (filter_mask);
1049 describe_XRectangle (char *name, XRectangle *r)
1052 stderr_out ("%s: NULL\n", name);
1054 stderr_out ("%s: x=%d y=%d w=%d h=%d\n",
1055 name, r->x, r->y, r->width, r->height);
1059 /* Print out elements of Event mask */
1060 /* Defines from X11/X.h */
1062 describe_event_mask (unsigned long mask)
1064 #define DESCRIBE_EVENT_MASK(bit) if ((bit) & mask) stderr_out (#bit " ")
1065 DESCRIBE_EVENT_MASK (NoEventMask);
1066 DESCRIBE_EVENT_MASK (KeyPressMask);
1067 DESCRIBE_EVENT_MASK (KeyReleaseMask);
1068 DESCRIBE_EVENT_MASK (ButtonPressMask);
1069 DESCRIBE_EVENT_MASK (ButtonReleaseMask);
1070 DESCRIBE_EVENT_MASK (EnterWindowMask);
1071 DESCRIBE_EVENT_MASK (LeaveWindowMask);
1072 DESCRIBE_EVENT_MASK (PointerMotionMask);
1073 DESCRIBE_EVENT_MASK (PointerMotionHintMask);
1074 DESCRIBE_EVENT_MASK (Button1MotionMask);
1075 DESCRIBE_EVENT_MASK (Button2MotionMask);
1076 DESCRIBE_EVENT_MASK (Button3MotionMask);
1077 DESCRIBE_EVENT_MASK (Button4MotionMask);
1078 DESCRIBE_EVENT_MASK (Button5MotionMask);
1079 DESCRIBE_EVENT_MASK (ButtonMotionMask);
1080 DESCRIBE_EVENT_MASK (KeymapStateMask);
1081 DESCRIBE_EVENT_MASK (ExposureMask);
1082 DESCRIBE_EVENT_MASK (VisibilityChangeMask);
1083 DESCRIBE_EVENT_MASK (StructureNotifyMask);
1084 DESCRIBE_EVENT_MASK (ResizeRedirectMask);
1085 DESCRIBE_EVENT_MASK (SubstructureNotifyMask);
1086 DESCRIBE_EVENT_MASK (SubstructureRedirectMask);
1087 DESCRIBE_EVENT_MASK (FocusChangeMask);
1088 DESCRIBE_EVENT_MASK (PropertyChangeMask);
1089 DESCRIBE_EVENT_MASK (ColormapChangeMask);
1090 DESCRIBE_EVENT_MASK (OwnerGrabButtonMask);
1091 #undef DESCRIBE_EVENT_MASK
1096 describe_XIMStyle (XIMStyle style)
1098 #define DESCRIBE_STYLE(bit) \
1099 if (bit & style) { \
1100 stderr_out (#bit " "); \
1103 DESCRIBE_STYLE (XIMPreeditArea);
1104 DESCRIBE_STYLE (XIMPreeditCallbacks);
1105 DESCRIBE_STYLE (XIMPreeditPosition);
1106 DESCRIBE_STYLE (XIMPreeditNothing);
1107 DESCRIBE_STYLE (XIMPreeditNone);
1108 DESCRIBE_STYLE (XIMStatusArea);
1109 DESCRIBE_STYLE (XIMStatusCallbacks);
1110 DESCRIBE_STYLE (XIMStatusNothing);
1111 DESCRIBE_STYLE (XIMStatusNone);
1112 #undef DESCRIBE_STYLE
1117 describe_XIMStyles (XIMStyles *p)
1120 stderr_out ("%d Style(s):\n", p->count_styles);
1121 for (i=0; i<p->count_styles ; i++) {
1122 describe_XIMStyle (p->supported_styles[i]);
1126 #endif /* DEBUG_SXEMACS */
1128 /* Random cruft follows */
1132 Unit_Test (struct frame *f, char * s)
1133 /* mrb unit testing */
1135 XrmValue fromVal, toVal;
1138 fromVal.size = strlen (s);
1139 toVal.addr = (XtPointer) &user_preferred_XIMStyles;
1140 toVal.size = sizeof (XIMStyles);
1142 if (XtConvertAndStore (FRAME_X_TEXT_WIDGET (f), XtRString, &fromVal,
1143 XtRXimStyles, &toVal) != False) {
1144 stderr_out ("Unit_Test: fromVal.addr=0x%x\n",fromVal.addr);
1145 stderr_out ("Unit_Test: fromVal.size=%d\n", fromVal.size);
1146 stderr_out ("Unit_Test: toVal.addr=0x%x\n", toVal.addr);
1147 stderr_out ("Unit_Test: toVal.size=%d\n", toVal.size);
1148 describe_XIMStyles ((XIMStyles *) toVal.addr);
1152 #endif /* XIM_XLIB only */
1155 /* Get a fontset for IM to use */
1157 x_init_fontset (struct device *d)
1159 Display *dpy = DEVICE_X_DISPLAY (d);
1161 char ** missing_charsets;
1162 int num_missing_charsets;
1163 char * default_string;
1164 /* char * font_set_string = "-dt-interface user-medium-r-normal\
1165 -s*-*-*-*-*-*-*-*-*";*/
1166 char *font_set_string =
1167 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*,"
1168 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0,"
1169 "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,"
1170 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0";
1172 DEVICE_X_FONTSET (d) = fontset =
1173 XCreateFontSet (dpy, font_set_string,
1175 &num_missing_charsets,
1178 if (fontset == NULL) {
1179 stderr_out("Unable to create fontset from string:\n%s\n",
1183 if (num_missing_charsets > 0) {
1185 stderr_out ("\nMissing charsets for fontset %s:\n",
1187 for (i=0; i < num_missing_charsets; i++) {
1188 stderr_out ("%s\n", missing_charsets[i]);
1190 XFreeStringList (missing_charsets);
1191 stderr_out ("Default string: %s\n", default_string);
1195 describe_XFontSet (fontset);