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 <config.h>
#include "lisp.h"
#include <X11/Xlocale.h> /* More portable than <locale.h> ? */
+#include <X11/Xlib.h>
#include "frame.h"
#include "device.h"
#include "window.h"
#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) \
"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;
- XtSetLanguageProc (NULL, (XtLanguageProc) NULL, NULL);
+ /* 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,
+ we should really do it manually and not use Xlib's dumb default routine */
+ /*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;
}
}
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), \
static XtResource resources[] =
{
/* name class represent'n field default value */
- res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, DefaultXIMStyles),
- res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, XtDefaultFontSet),
- res(XtNximForeground, XtCForeground, XtRPixel, fg, XtDefaultForeground),
- res(XtNximBackground, XtCBackground, XtRPixel, bg, XtDefaultBackground)
+ res(XtNximStyles, XtCXimStyles, XtRXimStyles, styles, (XtPointer) DefaultXIMStyles),
+ res(XtNfontSet, XtCFontSet, XtRFontSet, fontset, (XtPointer) XtDefaultFontSet),
+ res(XtNximForeground, XtCForeground, XtRPixel, fg, (XtPointer) XtDefaultForeground),
+ 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;
}
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)
{
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);
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));
}
int i;
XClientMessageEvent new_event;
-try_again:
+retry:
len = XwcLookupString (ic, x_key_event, composed_input_buf.data,
composed_input_buf.size, &keysym, &status);
switch (status)
{
case XBufferOverflow:
/* GROW_WC_STRING (&composed_input_buf, 32); mrb */
- goto try_again;
+ goto retry;
case XLookupChars:
break;
default:
#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),
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;
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)
}
}
#endif
+#endif /* XIM_XLIB only */
#if 0
/* Get a fontset for IM to use */