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 && 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 if ( snprintf (xwincmd, sizeof(xwincmd),
943 "xwininfo -id 0x%x >&2; xwininfo -events -id 0x%x >&2",
944 (int) win, (int) win) < sizeof(xwincmd) ) {
945 int exit_code = system (xwincmd);
946 if ( exit_code != 0 )
947 stderr_out("command '%s' failed with exit code %d",
950 stderr_out("Could not generate wininfo command line");
954 describe_XIC (XIC xic)
957 Window client_win=0, focus_win=0;
958 char *resourceName = NULL;
959 char *resourceClass = NULL;
960 char *bad_arg = NULL;
961 unsigned long filter_mask = NoEventMask;
962 XVaNestedList p_list, s_list;
963 XFontSet p_fontset = NULL, s_fontset = NULL;
964 Pixel p_fg=0, p_bg = 0, s_fg=0, s_bg = 0;
965 XRectangle *p_area = NULL, *s_area = NULL;
966 XRectangle *p_needed = NULL, *s_needed = NULL;
967 XPoint *p_spot = NULL;
969 /* Check for valid input context and method */
971 stderr_out ("Input method is NULL\n");
974 stderr_out ("XIMOfIC() returns NULL\n");
976 /* Print out Input Context Attributes */
977 p_list = XVaCreateNestedList (0,
978 XNFontSet, &p_fontset,
980 XNAreaNeeded, &p_needed,
981 XNSpotLocation, &p_spot,
986 s_list = XVaCreateNestedList (0,
987 XNFontSet, &s_fontset,
989 XNAreaNeeded, &s_needed,
994 bad_arg = XGetICValues(xic,
995 XNInputStyle, &style,
996 XNFilterEvents, &filter_mask,
997 XNClientWindow, &client_win,
998 XNFocusWindow, &focus_win,
999 XNResourceName, &resourceName,
1000 XNResourceClass, &resourceClass,
1001 XNPreeditAttributes, p_list,
1002 XNStatusAttributes, s_list,
1007 if (bad_arg != NULL) {
1008 stderr_out ("Couldn't get IC value: %s\n", bad_arg);
1010 stderr_out ("\nInput method context attributes:\n");
1011 stderr_out ("Style: "); describe_XIMStyle (style);
1012 stderr_out ("Client window: %lx\n", (unsigned long int)client_win);
1013 stderr_out ("Focus window: %lx\n", (unsigned long int)focus_win);
1014 stderr_out ("Preedit:\n");
1015 describe_XRectangle (" Area", p_area);
1016 describe_XRectangle (" Area needed", p_needed);
1017 stderr_out (" foreground: %lx\n", (unsigned long int)p_fg);
1018 stderr_out (" background: %lx\n", (unsigned long int)p_bg);
1019 stderr_out (" fontset: "); describe_XFontSet (p_fontset);
1020 stderr_out ("Status:\n");
1021 describe_XRectangle (" Area", s_area);
1022 describe_XRectangle (" Area needed", s_needed);
1023 stderr_out (" foreground: %lx\n", (unsigned long int)s_fg);
1024 stderr_out (" background: %lx\n", (unsigned long int)s_bg);
1025 stderr_out (" fontset: \n"); describe_XFontSet (s_fontset);
1026 stderr_out ("XNResourceName: %s\n", resourceName
1027 ? resourceName : "NULL");
1028 stderr_out ("XNResourceClass: %s\n", resourceClass
1029 ? resourceClass : "NULL");
1030 stderr_out ("XNFilterEvents: "); describe_event_mask (filter_mask);
1034 describe_XRectangle (char *name, XRectangle *r)
1037 stderr_out ("%s: NULL\n", name);
1039 stderr_out ("%s: x=%d y=%d w=%d h=%d\n",
1040 name, r->x, r->y, r->width, r->height);
1044 /* Print out elements of Event mask */
1045 /* Defines from X11/X.h */
1047 describe_event_mask (unsigned long mask)
1049 #define DESCRIBE_EVENT_MASK(bit) if ((bit) & mask) stderr_out (#bit " ")
1050 DESCRIBE_EVENT_MASK (NoEventMask);
1051 DESCRIBE_EVENT_MASK (KeyPressMask);
1052 DESCRIBE_EVENT_MASK (KeyReleaseMask);
1053 DESCRIBE_EVENT_MASK (ButtonPressMask);
1054 DESCRIBE_EVENT_MASK (ButtonReleaseMask);
1055 DESCRIBE_EVENT_MASK (EnterWindowMask);
1056 DESCRIBE_EVENT_MASK (LeaveWindowMask);
1057 DESCRIBE_EVENT_MASK (PointerMotionMask);
1058 DESCRIBE_EVENT_MASK (PointerMotionHintMask);
1059 DESCRIBE_EVENT_MASK (Button1MotionMask);
1060 DESCRIBE_EVENT_MASK (Button2MotionMask);
1061 DESCRIBE_EVENT_MASK (Button3MotionMask);
1062 DESCRIBE_EVENT_MASK (Button4MotionMask);
1063 DESCRIBE_EVENT_MASK (Button5MotionMask);
1064 DESCRIBE_EVENT_MASK (ButtonMotionMask);
1065 DESCRIBE_EVENT_MASK (KeymapStateMask);
1066 DESCRIBE_EVENT_MASK (ExposureMask);
1067 DESCRIBE_EVENT_MASK (VisibilityChangeMask);
1068 DESCRIBE_EVENT_MASK (StructureNotifyMask);
1069 DESCRIBE_EVENT_MASK (ResizeRedirectMask);
1070 DESCRIBE_EVENT_MASK (SubstructureNotifyMask);
1071 DESCRIBE_EVENT_MASK (SubstructureRedirectMask);
1072 DESCRIBE_EVENT_MASK (FocusChangeMask);
1073 DESCRIBE_EVENT_MASK (PropertyChangeMask);
1074 DESCRIBE_EVENT_MASK (ColormapChangeMask);
1075 DESCRIBE_EVENT_MASK (OwnerGrabButtonMask);
1076 #undef DESCRIBE_EVENT_MASK
1081 describe_XIMStyle (XIMStyle style)
1083 #define DESCRIBE_STYLE(bit) \
1084 if (bit & style) { \
1085 stderr_out (#bit " "); \
1088 DESCRIBE_STYLE (XIMPreeditArea);
1089 DESCRIBE_STYLE (XIMPreeditCallbacks);
1090 DESCRIBE_STYLE (XIMPreeditPosition);
1091 DESCRIBE_STYLE (XIMPreeditNothing);
1092 DESCRIBE_STYLE (XIMPreeditNone);
1093 DESCRIBE_STYLE (XIMStatusArea);
1094 DESCRIBE_STYLE (XIMStatusCallbacks);
1095 DESCRIBE_STYLE (XIMStatusNothing);
1096 DESCRIBE_STYLE (XIMStatusNone);
1097 #undef DESCRIBE_STYLE
1102 describe_XIMStyles (XIMStyles *p)
1105 stderr_out ("%d Style(s):\n", p->count_styles);
1106 for (i=0; i<p->count_styles ; i++) {
1107 describe_XIMStyle (p->supported_styles[i]);
1111 #endif /* DEBUG_SXEMACS */
1113 /* Random cruft follows */
1117 Unit_Test (struct frame *f, char * s)
1118 /* mrb unit testing */
1120 XrmValue fromVal, toVal;
1123 fromVal.size = strlen (s);
1124 toVal.addr = (XtPointer) &user_preferred_XIMStyles;
1125 toVal.size = sizeof (XIMStyles);
1127 if (XtConvertAndStore (FRAME_X_TEXT_WIDGET (f), XtRString, &fromVal,
1128 XtRXimStyles, &toVal) != False) {
1129 stderr_out ("Unit_Test: fromVal.addr=0x%x\n",fromVal.addr);
1130 stderr_out ("Unit_Test: fromVal.size=%d\n", fromVal.size);
1131 stderr_out ("Unit_Test: toVal.addr=0x%x\n", toVal.addr);
1132 stderr_out ("Unit_Test: toVal.size=%d\n", toVal.size);
1133 describe_XIMStyles ((XIMStyles *) toVal.addr);
1137 #endif /* XIM_XLIB only */
1140 /* Get a fontset for IM to use */
1142 x_init_fontset (struct device *d)
1144 Display *dpy = DEVICE_X_DISPLAY (d);
1146 char ** missing_charsets;
1147 int num_missing_charsets;
1148 char * default_string;
1149 /* char * font_set_string = "-dt-interface user-medium-r-normal\
1150 -s*-*-*-*-*-*-*-*-*";*/
1151 char *font_set_string =
1152 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*,"
1153 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0,"
1154 "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,"
1155 "-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0";
1157 DEVICE_X_FONTSET (d) = fontset =
1158 XCreateFontSet (dpy, font_set_string,
1160 &num_missing_charsets,
1163 if (fontset == NULL) {
1164 stderr_out("Unable to create fontset from string:\n%s\n",
1168 if (num_missing_charsets > 0) {
1170 stderr_out ("\nMissing charsets for fontset %s:\n",
1172 for (i=0; i < num_missing_charsets; i++) {
1173 stderr_out ("%s\n", missing_charsets[i]);
1175 XFreeStringList (missing_charsets);
1176 stderr_out ("Default string: %s\n", default_string);
1180 describe_XFontSet (fontset);