X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Finput-method-xlib.c;h=8a1f3cad6c42db5709c878ea128c68a0e1e3d533;hb=6e9175d270d5d8eea7cf6bbe4e3ae78b9955fb8c;hp=cb8a9b07c4d3c2ec8a576dc42d62aeca4e7ece5b;hpb=77dcef404dc78635f6ffa8f71a803d2bc7cc8921;p=chise%2Fxemacs-chise.git.1 diff --git a/src/input-method-xlib.c b/src/input-method-xlib.c index cb8a9b0..8a1f3ca 100644 --- a/src/input-method-xlib.c +++ b/src/input-method-xlib.c @@ -27,9 +27,51 @@ Boston, MA 02111-1307, USA. */ and X11 R6 release guide chapters on internationalized input, for further details */ +/* + Policy: + + The XIM is of the device, by the device, for the device. + The XIC is of each frame, by each frame, for each frame. + The exceptions are: + 1. Activate XICs on poor frames when the XIM is back. + 2. Deactivate all the XICs when the XIM goes down. + + Implementation: + + - Register a callback for an XIM when the X device is being initialized. + XIM_init_device (d) { XRegisterIMInstantiateCallback (); } + The "XRegisterIMInstantiateCallback" is called when an XIM become + available on the X display. + + - Catch the XIC when the frame is being initialized if XIM was available. + XIM_init_frame (f) { ... XCreateIC (); ... } + + - Release the XIC when the frame is being closed. + XIM_delete_frame (f) { ... FRAME_X_XIC (f) = NULL; ... } + "XIM_delete_frame" is a "DestroyCallback" function declared in + XIM_init_frame (); + + - Release all the XICs when the XIM was down accidentally. + In IMDestroyCallback: + DEVICE_FRAME_LOOP (...) { FRAME_X_XIC (f) = NULL; } + + - Re-enable XIC for all the frames which don't have XIC when the XIM + is back. + In IMInstantiateCallback: + DEVICE_FRAME_LOOP (...) { XIM_init_frame (f); } + + + Note: + + - Currently, we don't use XDestroyIC because of _XimProtoCloseIM + (internally registered as im->methods->close) does "Xfree (ic)". + + */ + #include #include "lisp.h" #include /* More portable than ? */ +#include #include "frame.h" #include "device.h" #include "window.h" @@ -38,10 +80,16 @@ Boston, MA 02111-1307, USA. */ #include "EmacsFrame.h" #include "events.h" -#ifndef XIM_XLIB -#error XIM_XLIB is not defined?? +#if !defined (XIM_XLIB) && !defined (USE_XFONTSET) +#error neither XIM_XLIB nor USE_XFONTSET is defined?? #endif +Lisp_Object Qxim_xlib; +#define xim_warn(str) warn_when_safe (Qxim_xlib, Qwarning, str); +#define xim_warn1(fmt, str) warn_when_safe (Qxim_xlib, Qwarning, fmt, str); +#define xim_info(str) warn_when_safe (Qxim_xlib, Qinfo, str); + +#ifdef XIM_XLIB /* XIM_XLIB specific */ /* Get/Set IC values for just one attribute */ #ifdef DEBUG_XEMACS #define XIC_Value(Get_Set, xic, name, attr, value) \ @@ -73,13 +121,17 @@ static char DefaultXIMStyles[] = "XIMPreeditNone|XIMStatusNone"; static XIMStyle best_style (XIMStyles *user, XIMStyles *xim); +#endif /* XIM_XLIB only */ + +/* This function is documented, but no prototype in the header files */ +EXTERN_C char * XSetIMValues(XIM, ...); void Initialize_Locale (void) { char *locale; - /* dverna - Nov. 98: ### DON'T DO THIS !!! The default XtLanguageProc + /* dverna - Nov. 98: #### DON'T DO THIS !!! The default XtLanguageProc routine calls setlocale(LC_ALL, lang) which fucks up our lower-level locale management, and especially the value of LC_NUMERIC. Anyway, since at this point, we don't know yet whether we're gonna need an X11 frame, @@ -87,31 +139,31 @@ Initialize_Locale (void) /*XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);*/ if ((locale = setlocale (LC_ALL, "")) == NULL) { - stderr_out ("Can't set locale.\n"); - stderr_out ("Using C locale instead.\n"); + xim_warn ("Can't set locale.\n" + "Using C locale instead.\n"); putenv ("LANG=C"); putenv ("LC_ALL=C"); if ((locale = setlocale (LC_ALL, "C")) == NULL) { - stderr_out ("Can't even set locale to `C'!\n"); + xim_warn ("Can't even set locale to `C'!\n"); return; } } if (!XSupportsLocale ()) { - stderr_out ("X Windows does not support locale `%s'\n", locale); - stderr_out ("Using C Locale instead\n"); + xim_warn1 ("X Windows does not support locale `%s'\n" + "Using C Locale instead\n", locale); putenv ("LANG=C"); putenv ("LC_ALL=C"); if ((locale = setlocale (LC_ALL, "C")) == NULL) { - stderr_out ("Can't even set locale to `C'!\n"); + xim_warn ("Can't even set locale to `C'!\n"); return; } if (!XSupportsLocale ()) { - stderr_out ("X Windows does not even support locale `C'!\n"); + xim_warn ("X Windows does not even support locale `C'!\n"); return; } } @@ -120,65 +172,164 @@ Initialize_Locale (void) if (XSetLocaleModifiers ("") == NULL) { - stderr_out ("XSetLocaleModifiers(\"\") failed\n"); - stderr_out ("Check the value of the XMODIFIERS environment variable.\n"); + xim_warn ("XSetLocaleModifiers(\"\") failed\n" + "Check the value of the XMODIFIERS environment variable.\n"); } } -/* Create X input method for device */ +#ifdef XIM_XLIB /* starting XIM specific codes */ + +/* Callbacks for IM are supported from X11R6 or later. */ +#ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK + +static Boolean xim_initted = False; + +/* Called from when XIM is destroying. + Clear all the XIC when the XIM was destroying... */ +static void +IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data) +{ + struct device *d = (struct device *)client_data; + Lisp_Object tail; + + DEVICE_FRAME_LOOP (tail, d) + { + struct frame *target_frame = XFRAME (XCAR (tail)); + if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame)) + { + /* XDestroyIC (FRAME_X_XIC (target_frame)); */ + FRAME_X_XIC (target_frame) = NULL; + } + } + + DEVICE_X_XIM (d) = NULL; + xim_initted = False; + return; +} + +/* This is registered in XIM_init_device (when DEVICE is initializing). + This activates XIM when XIM becomes available. */ +static void +IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data) +{ + struct device *d = (struct device *)client_data; + XIM xim; + char *name, *class; + XIMCallback ximcallback; + Lisp_Object tail; + + /* if no xim is presented, initialize xim ... */ + if ( xim_initted == False ) + { + xim_initted = True; + XtGetApplicationNameAndClass (dpy, &name, &class); + DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class); + + /* destroy callback for im */ + ximcallback.callback = (XIMProc) IMDestroyCallback; + ximcallback.client_data = (XPointer) d; + XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL); + } + + /* activate XIC on all the X frames... */ + DEVICE_FRAME_LOOP (tail, d) + { + struct frame *target_frame = XFRAME (XCAR (tail)); + if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame)) + { + XIM_init_frame (target_frame); + } + } + return; +} +#endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */ + +/* Initialize XIM for X device. + Register the use of XIM using XRegisterIMInstantiateCallback. */ void XIM_init_device (struct device *d) { +#ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK /* X11R6+ */ + DEVICE_X_XIM (d) = NULL; + XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL, +#ifdef XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE + /* The sixth parameter is of type + XPointer in XFree86 but (XPointer *) + on most other X11's. */ + (XIDProc) IMInstantiateCallback, + (XPointer) d +#else /* X Consortium prototype */ + (XIMProc) IMInstantiateCallback, + (XPointer *) d +#endif /* XREGISTERIMINSTANTIATECALLBACK_NONSTANDARD_PROTOTYPE */ + ); + return; +#else /* pre-X11R6 */ Display *dpy = DEVICE_X_DISPLAY (d); char *name, *class; XIM xim; XtGetApplicationNameAndClass (dpy, &name, &class); - DEVICE_X_XIM (d) = xim = XOpenIM (dpy, XtDatabase (dpy), name, class); - if (xim == NULL) { - stderr_out ("Warning: XOpenIM() failed...no input server available\n"); + xim_warn ("XOpenIM() failed...no input server available\n"); return; } else { - /* Get supported styles */ XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES (d), NULL); -#ifdef DEBUG_XIM - describe_XIM (xim); -#endif + return; + } +#endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */ +} + + +/* + * For the frames + */ + +/* Callback for the deleting frame. */ +static void +XIM_delete_frame (Widget w, XtPointer client_data, XtPointer call_data) +{ + struct frame *f = (struct frame *) client_data; + struct device *d = XDEVICE (FRAME_DEVICE (f)); + + if (DEVICE_X_XIM (d)) + { + if (FRAME_X_XIC (f)) + { + XDestroyIC (FRAME_X_XIC (f)); + FRAME_X_XIC (f) = NULL; + } } + return; } -/* Create an X input context for this frame. */ +/* Initialize XIC for new frame. + Create an X input context (XIC) for this frame. */ void XIM_init_frame (struct frame *f) { struct device *d = XDEVICE (FRAME_DEVICE (f)); - XIM xim = DEVICE_X_XIM (d); - XIC xic; + XIM xim; Widget w = FRAME_X_TEXT_WIDGET (f); Window win = XtWindow (w); - XRectangle p_area = {0,0,1,1}, s_area={0,0,1,1}; + XRectangle p_area = {0,0,1,1}, s_area = {0,0,1,1}; XPoint spot = {0,0}; XIMStyle style; XVaNestedList p_list, s_list; - typedef struct { XIMStyles styles; XFontSet fontset; Pixel fg; Pixel bg; + char *inputmethod; } xic_vars_t; - xic_vars_t xic_vars; - - /* mrb: #### Fix so that background and foreground is set from - default face, rather than foreground and background resources, or - that the user can use set-frame-parameters to set xic attributes */ + XIC xic; #define res(name, class, representation, field, default_value) \ { name, class, representation, sizeof(xic_vars.field), \ @@ -193,64 +344,70 @@ XIM_init_frame (struct frame *f) res(XtNximBackground, XtCBackground, XtRPixel, bg, (XtPointer) XtDefaultBackground) }; - assert (win != 0 && w != NULL && d != NULL); + + xim = DEVICE_X_XIM (d); if (!xim) - { /* No input method? */ - FRAME_X_XIC (f) = NULL; + { return; } + w = FRAME_X_TEXT_WIDGET (f); + + /* + * initialize XIC + */ + if (FRAME_X_XIC (f)) return; XtGetApplicationResources (w, &xic_vars, resources, XtNumber (resources), NULL, 0); - if (!xic_vars.fontset) { - stderr_out ("Can't get fontset resource for Input Method\n"); + xim_warn ("Can't get fontset resource for Input Method\n"); FRAME_X_XIC (f) = NULL; return; } + /* construct xic */ + XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES(d), NULL); FRAME_X_XIC_STYLE (f) = style = - best_style (&xic_vars.styles, DEVICE_X_XIM_STYLES (d)); + best_style (&xic_vars.styles, (XIMStyles *)DEVICE_X_XIM_STYLES(d)); - /* Hopefully we don't have to conditionalize the following based on - style; the IM should ignore values it doesn't use */ p_list = XVaCreateNestedList (0, - XNArea, &p_area, - XNSpotLocation, &spot, - XNForeground, xic_vars.fg, - XNBackground, xic_vars.bg, - XNFontSet, xic_vars.fontset, - NULL); + XNArea, &p_area, + XNSpotLocation, &spot, + XNForeground, xic_vars.fg, + XNBackground, xic_vars.bg, + XNFontSet, xic_vars.fontset, + NULL); s_list = XVaCreateNestedList (0, - XNArea, &s_area, - XNForeground, xic_vars.fg, - XNBackground, xic_vars.bg, - XNFontSet, xic_vars.fontset, - NULL); + XNArea, &s_area, + XNForeground, xic_vars.fg, + XNBackground, xic_vars.bg, + XNFontSet, xic_vars.fontset, + NULL); + FRAME_X_XIC (f) = xic = XCreateIC (xim, - XNInputStyle, style, - XNClientWindow, win, - XNFocusWindow, win, - XNPreeditAttributes, p_list, - XNStatusAttributes, s_list, - NULL); + XNInputStyle, style, + XNClientWindow, win, + XNFocusWindow, win, + XNPreeditAttributes, p_list, + XNStatusAttributes, s_list, + NULL); XFree (p_list); XFree (s_list); if (!xic) { - stderr_out ("Warning: XCreateIC failed\n"); + xim_warn ("Warning: XCreateIC failed.\n"); return; } if (style & XIMPreeditPosition) - { /* Init spot to invalid values */ - XPoint *frame_spot = &(FRAME_X_XIC_SPOT (f)); + { + XPoint *frame_spot = &(FRAME_X_XIC_SPOT(f)); frame_spot->x = frame_spot->y = -1; } @@ -258,21 +415,29 @@ XIM_init_frame (struct frame *f) XSetICFocus (xic); -#ifdef DEBUG_XIM - describe_XIC (xic); +#ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK + /* when frame is going to be destroyed (closed) */ + XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback, + XIM_delete_frame, (XtPointer)f); #endif } + void XIM_SetGeometry (struct frame *f) { - XIC xic = FRAME_X_XIC (f); - XIMStyle style = FRAME_X_XIC_STYLE (f); + XIC xic; + XIMStyle style; XRectangle area; - if (!xic || !f) + if (!f) return; + xic = FRAME_X_XIC (f); + if (!xic) + return; + + style = FRAME_X_XIC_STYLE (f); if (style & XIMStatusArea) { /* Place Status Area in bottom right corner */ @@ -336,7 +501,7 @@ XIM_SetSpotLocation (struct frame *f, int x, int y) spot->x = (short) x; spot->y = (short) y; - /* ### FIX: Must make sure spot fits within Preedit Area */ + /* #### FIX: Must make sure spot fits within Preedit Area */ XIC_Value (Set, xic, XNPreeditAttributes, XNSpotLocation, spot); #ifdef DEBUG_XIM stderr_out ("Spot: %d %d\n", spot->x, spot->y); @@ -346,7 +511,7 @@ XIM_SetSpotLocation (struct frame *f, int x, int y) void XIM_focus_event (struct frame *f, int in_p) { - if (FRAME_X_XIC (f)) + if (FRAME_X_XIC (f) /* && FRAME_X_XIM_REGISTERED(f) */) (in_p ? XSetICFocus : XUnsetICFocus) (FRAME_X_XIC (f)); } @@ -396,7 +561,7 @@ retry: case XLookupChars: break; default: - abort (); + ABORT (); } new_event.type = ClientMessage; @@ -464,9 +629,9 @@ EmacsXtCvtStringToXIMStyles ( #define STYLE_INFO(style) { style, #style, sizeof(#style) } static struct XIMStyleInfo { - CONST XIMStyle style; - CONST char * CONST name; - CONST int namelen; + const XIMStyle style; + const char * const name; + const int namelen; } emacs_XIMStyleInfo[] = { STYLE_INFO (XIMPreeditPosition|XIMStatusArea), STYLE_INFO (XIMPreeditPosition|XIMStatusNothing), @@ -482,9 +647,9 @@ EmacsXtCvtStringToXIMStyles ( char *s = (char *) fromVal->addr; char *end = s + fromVal->size; - XIMStyles * CONST p = (XIMStyles *) toVal->addr; - CONST char * CONST delimiter = " \t\n\r:;," ; - CONST int max_styles = XtNumber(emacs_XIMStyleInfo); + XIMStyles * const p = (XIMStyles *) toVal->addr; + const char * const delimiter = " \t\n\r:;," ; + const int max_styles = XtNumber(emacs_XIMStyleInfo); int i; char *c; @@ -637,6 +802,65 @@ best_style (XIMStyles *user, XIMStyles *xim) return DEFAULTStyle; /* Default Style */ } +/* These lisp-callable functions will be sealed until xim-leim is needed. + Oct 22 1999 - kazz */ +#if 0 +/* + * External callable function for XIM + */ +DEFUN ("x-open-xim", Fx_open_xim, 1, 1, 0, /* +Open the XIC on the frame if XIM is available. +Commonly, use this as \(x-open-xim \(selected-frame)). +If the frame is not on X device, return signal. +If XIC is created successfully return t. If not return nil. +*/ + (frame)) +{ + struct frame *f; + + CHECK_LIVE_FRAME (frame); + f = XFRAME (frame); + if (!FRAME_X_P (f)) + return signal_simple_error ("This frame is not on X device", frame); + + XIM_init_frame (f); + return FRAME_X_XIC (f) ? Qt : Qnil; +} + +DEFUN ("x-close-xim", Fx_close_xim, 1, 1, 0, /* +Close the XIC on the frame if it exists. +Commonly, use this as \(x-close-xim \(selected-frame)). +If the frame is not on X device, return signal. +Otherwise, it destroys the XIC if it exists, then returns t anyway. +*/ + (frame)) +{ + struct frame *f; + struct device *d; + + CHECK_LIVE_FRAME (frame); + f = XFRAME (frame); + if (!FRAME_X_P (f)) + return signal_simple_error ("This frame is not on X device", frame); + + d = XDEVICE (FRAME_DEVICE (f)); + if (DEVICE_X_XIM (d)) { + /* XDestroyIC (FRAME_X_XIC (XFRAME (f))); */ + FRAME_X_XIC (XFRAME (f)) = NULL; + } + return Qt; +} +#endif /* if 0 */ + +void +syms_of_input_method_xlib (void) +{ + defsymbol (&Qxim_xlib, "xim-xlib"); +#if 0 /* see above */ + DEFSUBR (Fx_open_xim); + DEFSUBR (Fx_close_xim); +#endif +} void vars_of_input_method_xlib (void) @@ -898,6 +1122,7 @@ Unit_Test (struct frame *f, char * s) } } #endif +#endif /* XIM_XLIB only */ #if 0 /* Get a fontset for IM to use */