(U+6215): Apply new conventions for glyph granularity.
[chise/xemacs-chise.git.1] / src / input-method-xlib.c
index 4d3ccad..8a1f3ca 100644 (file)
@@ -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 <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"
@@ -38,13 +80,16 @@ Boston, MA 02111-1307, USA.  */
 #include "EmacsFrame.h"
 #include "events.h"
 
-#include <X11/IntrinsicP.h>
-#include <X11/Xaw/XawImP.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)                     \
@@ -75,16 +120,18 @@ static char DefaultXIMStyles[] =
 "XIMPreeditNone|XIMStatusNothing\n"
 "XIMPreeditNone|XIMStatusNone";
 
-static Boolean xim_initted = False;
-
 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,
@@ -92,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;
         }
     }
@@ -125,55 +172,147 @@ 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");
     }
 }
 
-/******************************************************************/
-/*                     Input method using xlib                    */
-/******************************************************************/
+#ifdef XIM_XLIB /* starting XIM specific codes */
 
-/*
- * called from when XIM is destroying
- */
+/* 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 frame *f = (struct frame *) client_data;
-  struct device *d = XDEVICE (FRAME_DEVICE (f));
+  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_XIC (target_frame))
+      if (FRAME_X_P (target_frame) && FRAME_X_XIC (target_frame))
        {
-         XDestroyIC (FRAME_X_XIC (target_frame));
+         /* XDestroyIC (FRAME_X_XIC (target_frame)); */
          FRAME_X_XIC (target_frame) = NULL;
        }
     }
 
-#if 0
-  if ( DEVICE_X_XIM (d) )
+  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)
     {
-      stderr_out ("NULLing d->xim...\n");
-      /* DEVICE_X_XIM (d) = NULL; */
+      struct frame *target_frame = XFRAME (XCAR (tail));
+      if (FRAME_X_P (target_frame) && !FRAME_X_XIC (target_frame))
+       {
+         XIM_init_frame (target_frame);
+       }
     }
-#endif
+  return;
+}
+#endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
 
-  xim_initted = False;
+/* 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)
+    {
+      xim_warn ("XOpenIM() failed...no input server available\n");
+      return;
+    }
+  else
+    {
+      XGetIMValues (xim, XNQueryInputStyle, &DEVICE_X_XIM_STYLES (d), NULL);
+      return;
+    }
+#endif /* HAVE_XREGISTERIMINSTANTIATECALLBACK */
 }
 
+
 /*
- * called from when FRAME is initializing
+ * For the frames
  */
+
+/* Callback for the deleting frame. */
 static void
-IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
+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;
+}
+
+/* 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;
   Widget w = FRAME_X_TEXT_WIDGET (f);
   Window win = XtWindow (w);
@@ -181,7 +320,6 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
   XPoint spot = {0,0};
   XIMStyle style;
   XVaNestedList p_list, s_list;
-  char *name, *class;
   typedef struct
   {
     XIMStyles styles;
@@ -191,7 +329,6 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
     char      *inputmethod;
   } xic_vars_t;
   xic_vars_t xic_vars;
-  XIMCallback ximcallback;
   XIC xic;
 
 #define res(name, class, representation, field, default_value) \
@@ -204,29 +341,15 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
     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),
-    res(XtNinputMethod,   XtCInputMethod, XtRString,   inputmethod, (XtPointer) NULL)
+    res(XtNximBackground, XtCBackground, XtRPixel,     bg,      (XtPointer) XtDefaultBackground)
   };
 
-  /* ---------- beginning of the action ---------- */
 
-  /*
-   * 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);
+  xim = DEVICE_X_XIM (d);
 
-      /* destroy callback for im */
-      ximcallback.callback = IMDestroyCallback;
-      ximcallback.client_data = (XPointer) f;
-      XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
-    }
-  else
+  if (!xim)
     {
-      xim = DEVICE_X_XIM (d);
+      return;
     }
 
   w = FRAME_X_TEXT_WIDGET (f);
@@ -234,13 +357,13 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
   /*
    * initialize XIC
    */
-  if ( FRAME_X_XIC (f) ) return;
+  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;
     }
@@ -278,7 +401,7 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
 
   if (!xic)
     {
-      stderr_out ("Warning: XCreateIC failed.\n");
+      xim_warn ("Warning: XCreateIC failed.\n");
       return;
     }
 
@@ -292,73 +415,29 @@ IMInstantiateCallback (Display *dpy, XPointer client_data, XPointer call_data)
 
   XSetICFocus (xic);
 
-  return;
-}
-
-/* Create X input method for device */
-void
-XIM_init_device (struct device *d)
-{
-  /* do nothing here */
-  return;
-}
-
-/* Callback for when the frame was deleted (closed) */
-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));
-  Display *dpy = DEVICE_X_DISPLAY (d);
-
-  XUnregisterIMInstantiateCallback (dpy, NULL, NULL, NULL,
-                                   IMInstantiateCallback, (XPointer) f);
-
-  if (FRAME_X_XIC (f))
-    {
-      XDestroyIC (FRAME_X_XIC (f));
-      FRAME_X_XIC (f) = NULL;
-    }
-  return;
-}
-
-/* Create an X input context for this frame.
-   -  Register the IM to be initiated later using XRegisterIMInstantiateCallback
- */
-void
-XIM_init_frame (struct frame *f)
-{
-  struct device *d = XDEVICE (FRAME_DEVICE (f));
-
-  XRegisterIMInstantiateCallback (DEVICE_X_DISPLAY (d), NULL, NULL, NULL,
-                                 IMInstantiateCallback, (XPointer) f);
-
-#if 0
-  if ( FRAME_X_XIC (f) )
-    return;
-#endif
-  if ( ! DEVICE_X_XIM (d) )
-    {
-      stderr_out ("X Input Method open failed. Waiting IM to be enabled.\n");
-    }
-
+#ifdef HAVE_XREGISTERIMINSTANTIATECALLBACK
   /* when frame is going to be destroyed (closed) */
   XtAddCallback (FRAME_X_TEXT_WIDGET(f), XNDestroyCallback,
                 XIM_delete_frame, (XtPointer)f);
-  return;
+#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 */
@@ -422,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);
@@ -482,7 +561,7 @@ retry:
     case XLookupChars:
       break;
     default:
-      abort ();
+      ABORT ();
     }
 
   new_event.type = ClientMessage;
@@ -550,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),
@@ -568,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;
 
@@ -723,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)
@@ -984,6 +1122,7 @@ Unit_Test (struct frame *f, char * s)
     }
 }
 #endif
+#endif /* XIM_XLIB only */
 
 #if 0
 /* Get a fontset for IM to use */