(x_set_menu_bar_lines_1): Adjust window's orig_top and
[bpt/emacs.git] / src / xfns.c
index 143b870..dafee87 100644 (file)
@@ -42,6 +42,7 @@ Boston, MA 02111-1307, USA.  */
 #include "fontset.h"
 #include "systime.h"
 #include "termhooks.h"
+#include "atimer.h"
 
 #ifdef HAVE_X_WINDOWS
 
@@ -347,6 +348,8 @@ x_window_to_frame (dpyinfo, wdesc)
       f = XFRAME (frame);
       if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
+      if (f->output_data.x->busy_window == wdesc)
+       return f;
 #ifdef USE_X_TOOLKIT
       if ((f->output_data.x->edit_widget 
           && XtWindow (f->output_data.x->edit_widget) == wdesc)
@@ -374,34 +377,40 @@ x_any_window_to_frame (dpyinfo, wdesc)
      int wdesc;
 {
   Lisp_Object tail, frame;
-  struct frame *f;
+  struct frame *f, *found;
   struct x_output *x;
 
-  for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+  found = NULL;
+  for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
     {
       frame = XCAR (tail);
       if (!GC_FRAMEP (frame))
         continue;
+      
       f = XFRAME (frame);
-      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
-       continue;
-      x = f->output_data.x;
-      /* This frame matches if the window is any of its widgets.  */
-      if (x->widget)
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
        {
-         if (wdesc == XtWindow (x->widget) 
-             || wdesc == XtWindow (x->column_widget) 
-             || wdesc == XtWindow (x->edit_widget))
-           return f;
-         /* Match if the window is this frame's menubar.  */
-         if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
-           return f;
+         /* This frame matches if the window is any of its widgets.  */
+         x = f->output_data.x;
+         if (x->busy_window == wdesc)
+           found = f;
+         else if (x->widget)
+           {
+             if (wdesc == XtWindow (x->widget) 
+                 || wdesc == XtWindow (x->column_widget) 
+                 || wdesc == XtWindow (x->edit_widget))
+               found = f;
+             /* Match if the window is this frame's menubar.  */
+             else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
+               found = f;
+           }
+         else if (FRAME_X_WINDOW (f) == wdesc)
+           /* A tooltip frame.  */
+           found = f;
        }
-      else if (FRAME_X_WINDOW (f) == wdesc)
-       /* A tooltip frame.  */
-       return f;
     }
-  return 0;
+  
+  return found;
 }
 
 /* Likewise, but exclude the menu bar widget.  */
@@ -425,7 +434,9 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc)
        continue;
       x = f->output_data.x;
       /* This frame matches if the window is any of its widgets.  */
-      if (x->widget)
+      if (x->busy_window == wdesc)
+       return f;
+      else if (x->widget)
        {
          if (wdesc == XtWindow (x->widget) 
              || wdesc == XtWindow (x->column_widget) 
@@ -1237,7 +1248,7 @@ x_defined_color (f, color, color_def, alloc)
   Display *display = FRAME_X_DISPLAY (f);
 
   BLOCK_INPUT;
-  screen_colormap = DefaultColormap (display, XDefaultScreen (display));
+  screen_colormap = FRAME_X_COLORMAP (f);
 
   status = XParseColor (display, screen_colormap, color, color_def);
   if (status && alloc) 
@@ -1314,37 +1325,44 @@ x_defined_color (f, color, color_def, alloc)
     return 0;
 }
 
-/* Given a string ARG naming a color, compute a pixel value from it
-   suitable for screen F.
-   If F is not a color screen, return DEF (default) regardless of what
-   ARG says.  */
+
+/* Return the pixel color value for color COLOR_NAME on frame F.  If F
+   is a monochrome frame, return MONO_COLOR regardless of what ARG says.
+   Signal an error if color can't be allocated.  */
 
 int
-x_decode_color (f, arg, def)
+x_decode_color (f, color_name, mono_color)
      FRAME_PTR f;
-     Lisp_Object arg;
-     int def;
+     Lisp_Object color_name;
+     int mono_color;
 {
   XColor cdef;
 
-  CHECK_STRING (arg, 0);
+  CHECK_STRING (color_name, 0);
 
-  if (strcmp (XSTRING (arg)->data, "black") == 0)
+#if 0 /* Don't do this.  It's wrong when we're not using the default
+        colormap, it makes freeing difficult, and it's probably not
+        an important optimization.  */
+  if (strcmp (XSTRING (color_name)->data, "black") == 0)
     return BLACK_PIX_DEFAULT (f);
-  else if (strcmp (XSTRING (arg)->data, "white") == 0)
+  else if (strcmp (XSTRING (color_name)->data, "white") == 0)
     return WHITE_PIX_DEFAULT (f);
+#endif
 
+  /* Return MONO_COLOR for monochrome frames.  */
   if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
-    return def;
+    return mono_color;
 
   /* x_defined_color is responsible for coping with failures
      by looking for a near-miss.  */
-  if (x_defined_color (f, XSTRING (arg)->data, &cdef, 1))
+  if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
     return cdef.pixel;
 
   Fsignal (Qerror, Fcons (build_string ("undefined color"),
-                         Fcons (arg, Qnil)));
+                         Fcons (color_name, Qnil)));
 }
+
+
 \f
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
    the previous value of that parameter, NEW_VALUE is the new value.  */
@@ -1523,13 +1541,9 @@ x_set_mouse_color (f, arg, oldval)
 
     fore_color.pixel = f->output_data.x->mouse_pixel;
     back_color.pixel = mask_color;
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
+    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                 &fore_color);
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
+    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                 &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), cursor,
                    &fore_color, &back_color);
@@ -1901,6 +1915,11 @@ x_set_menu_bar_lines_1 (window, n)
   XSETFASTINT (w->top, XFASTINT (w->top) + n);
   XSETFASTINT (w->height, XFASTINT (w->height) - n);
 
+  if (INTEGERP (w->orig_top))
+    XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
+  if (INTEGERP (w->orig_height))
+    XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
+
   /* Handle just the top child in a vertical split.  */
   if (!NILP (w->vchild))
     x_set_menu_bar_lines_1 (w->vchild, n);
@@ -2504,8 +2523,6 @@ display_x_get_resource (dpyinfo, attribute, class, component, subclass)
   char *name_key;
   char *class_key;
 
-  check_x ();
-
   CHECK_STRING (attribute, 0);
   CHECK_STRING (class, 0);
 
@@ -3046,70 +3063,291 @@ hack_wm_protocols (f, widget)
 #endif
 
 
-/* Create input method and input context for frame F.  Set FRAME_XIM
-   (F) and FRAME_XIC (F).  */
+\f
+/* Support routines for XIC (X Input Context).  */
 
-static void
-x_create_im (f)
+#ifdef HAVE_X_I18N
+
+static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
+static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
+
+
+/* Supported XIM styles, ordered by preferenc.  */
+
+static XIMStyle supported_xim_styles[] =
+{
+  XIMPreeditPosition | XIMStatusArea,
+  XIMPreeditPosition | XIMStatusNothing,
+  XIMPreeditPosition | XIMStatusNone,
+  XIMPreeditNothing | XIMStatusArea,
+  XIMPreeditNothing | XIMStatusNothing,
+  XIMPreeditNothing | XIMStatusNone,
+  XIMPreeditNone | XIMStatusArea,
+  XIMPreeditNone | XIMStatusNothing,
+  XIMPreeditNone | XIMStatusNone,
+  0,
+};
+
+
+/* Create an X fontset on frame F with base font name
+   BASE_FONTNAME.. */
+
+static XFontSet
+xic_create_xfontset (f, base_fontname)
      struct frame *f;
+     char *base_fontname;
 {
-  FRAME_XIM (f) = 0;
-  FRAME_XIC (f) = 0;
+  XFontSet xfs;
+  char **missing_list;
+  int missing_count;
+  char *def_string;
   
-#ifdef HAVE_X_I18N
+  xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
+                       base_fontname, &missing_list,
+                       &missing_count, &def_string);
+  if (missing_list)
+    XFreeStringList (missing_list);
+  
+  /* No need to free def_string. */
+  return xfs;
+}
+
+
+/* Value is the best input style, given user preferences USER (already
+   checked to be supported by Emacs), and styles supported by the
+   input method XIM.  */
+
+static XIMStyle
+best_xim_style (user, xim)
+     XIMStyles *user;
+     XIMStyles *xim;
+{
+  int i, j;
+
+  for (i = 0; i < user->count_styles; ++i)
+    for (j = 0; j < xim->count_styles; ++j)
+      if (user->supported_styles[i] == xim->supported_styles[j])
+       return user->supported_styles[i];
+
+  /* Return the default style.  */
+  return XIMPreeditNothing | XIMStatusNothing;
+}
+
+/* Create XIC for frame F. */
+
+void
+create_frame_xic (f)
+     struct frame *f;
+{
 #ifndef X_I18N_INHIBITED
-  { 
-    XIM xim;
-    XIC xic = NULL;
-    XIMStyles *styles;
-    XIMStyle input_style = XIMPreeditNothing | XIMStatusNothing;
-    int i, n;
-
-    xim = XOpenIM (FRAME_X_DISPLAY(f), NULL, NULL, NULL);
-    if (!xim)
-      return;
-    
-    if (XGetIMValues (xim, XNQueryInputStyle, &styles, NULL)
-       || !styles)
-      {
-       /* Input method doesn't support any input style.  */
-       XCloseIM (xim);
-       return;
-      }
+  XIM xim;
+  XIC xic = NULL;
+  XFontSet xfs = NULL;
+  static XIMStyle xic_style;
 
-    /* See if input_style is supported.  Give up if it isn't.  */
-    n = styles->count_styles;
-    for (i = 0; i < n; ++i)
-      if (styles->supported_styles[i] == input_style)
-       break;
-    
-    XFree (styles);
-    if (i == n)
-      {
-       XCloseIM (xim);
-       return;
-      }
+  if (FRAME_XIC (f))
+    return;
+  
+  xim = FRAME_X_XIM (f);
+  if (xim)
+    {
+      XRectangle s_area;
+      XPoint spot;
+      XVaNestedList preedit_attr;
+      XVaNestedList status_attr;
+      char *base_fontname;
+      int fontset;
+
+      s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
+      spot.x = 0; spot.y = 1;
+      /* Create X fontset. */
+      fontset = FRAME_FONTSET (f);
+      if (fontset < 0)
+       base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+      else
+       {
+         struct fontset_info *fontsetp;
+         int len = 0;
+         int i;
+         
+         fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
+         for (i = 0; i <= MAX_CHARSET; i++)
+           if (fontsetp->fontname[i])
+             len += strlen (fontsetp->fontname[i]) + 1;
+         base_fontname = alloca (len);
+         strcpy (base_fontname, fontsetp->fontname[CHARSET_ASCII]);
+         for (i = MIN_CHARSET_OFFICIAL_DIMENSION1; i <= MAX_CHARSET; i++)
+           if (fontsetp->fontname[i])
+             {
+               strcat (base_fontname, ",");
+               strcat (base_fontname, fontsetp->fontname[i]);
+             }
+       }
+      xfs = xic_create_xfontset (f, base_fontname);
 
-    /* Create the input context.  */
-    xic = XCreateIC (xim,  
-                    XNInputStyle,   input_style,
-                    XNClientWindow, FRAME_X_WINDOW(f),
-                    XNFocusWindow,  FRAME_X_WINDOW(f),
-                    NULL);
-    
-    if (!xic)
-      {
-       XCloseIM (xim);
-       return;
-      }
+      /* Determine XIC style.  */
+      if (xic_style == 0)
+       {
+         XIMStyles supported_list;
+         supported_list.count_styles = (sizeof supported_xim_styles
+                                        / sizeof supported_xim_styles[0]);
+         supported_list.supported_styles = supported_xim_styles;
+         xic_style = best_xim_style (&supported_list,
+                                     FRAME_X_XIM_STYLES (f));
+       }
 
-    FRAME_XIM (f) = xim;
-    FRAME_XIC (f) = xic;
-  }
+      preedit_attr = XVaCreateNestedList (0,
+                                         XNFontSet, xfs,
+                                         XNForeground,
+                                         FRAME_FOREGROUND_PIXEL (f),
+                                         XNBackground,
+                                         FRAME_BACKGROUND_PIXEL (f),
+                                         (xic_style & XIMPreeditPosition
+                                          ? XNSpotLocation
+                                          : NULL),
+                                         &spot,
+                                         NULL);
+      status_attr = XVaCreateNestedList (0,
+                                        XNArea,
+                                        &s_area,
+                                        XNFontSet,
+                                        xfs,
+                                        XNForeground,
+                                        FRAME_FOREGROUND_PIXEL (f),
+                                        XNBackground,
+                                        FRAME_BACKGROUND_PIXEL (f),
+                                        NULL);
+
+      xic = XCreateIC (xim,
+                      XNInputStyle, xic_style,
+                      XNClientWindow, FRAME_X_WINDOW(f),
+                      XNFocusWindow, FRAME_X_WINDOW(f),
+                      XNStatusAttributes, status_attr,
+                      XNPreeditAttributes, preedit_attr,
+                      NULL);
+      XFree (preedit_attr);
+      XFree (status_attr);
+    }
+  
+  FRAME_XIC (f) = xic;
+  FRAME_XIC_STYLE (f) = xic_style;
+  FRAME_XIC_FONTSET (f) = xfs;
+#else /* X_I18N_INHIBITED */
+  FRAME_XIC (f) = NULL;
+  FRAME_XIC_STYLE (f) = 0;
+  FRAME_XIC_FONTSET (f) = NULL;
 #endif /* X_I18N_INHIBITED */
-#endif /* HAVE_X_I18N */
 }
 
+
+/* Destroy XIC and free XIC fontset of frame F, if any. */
+
+void
+free_frame_xic (f)
+     struct frame *f;
+{
+  if (FRAME_XIC (f) == NULL)
+    return;
+  
+  XDestroyIC (FRAME_XIC (f));
+  if (FRAME_XIC_FONTSET (f))
+    XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+
+  FRAME_XIC (f) = NULL;
+  FRAME_XIC_FONTSET (f) = NULL;
+}
+
+
+/* Place preedit area for XIC of window W's frame to specified
+   pixel position X/Y.  X and Y are relative to window W.  */
+
+void
+xic_set_preeditarea (w, x, y)
+     struct window *w;
+     int x, y;
+{
+  struct frame *f = XFRAME (w->frame);
+  XVaNestedList attr;
+  XPoint spot;
+      
+  spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
+  spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
+  attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
+  XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+  XFree (attr);
+}
+
+
+/* Place status area for XIC in bottom right corner of frame F.. */
+
+void
+xic_set_statusarea (f)
+     struct frame *f;
+{
+  XIC xic = FRAME_XIC (f);
+  XVaNestedList attr;
+  XRectangle area;
+  XRectangle *needed;
+
+  /* Negotiate geometry of status area.  If input method has existing
+     status area, use its current size.  */
+  area.x = area.y = area.width = area.height = 0;
+  attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
+  XSetICValues (xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+  
+  attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
+  XGetICValues (xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+
+  if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
+    {
+      attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
+      XGetICValues (xic, XNStatusAttributes, attr, NULL);
+      XFree (attr);
+    }
+
+  area.width  = needed->width;
+  area.height = needed->height;
+  area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
+  area.y = (PIXEL_HEIGHT (f) - area.height
+           - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
+  XFree (needed);
+
+  attr = XVaCreateNestedList (0, XNArea, &area, NULL);
+  XSetICValues(xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+}
+
+
+/* Set X fontset for XIC of frame F, using base font name
+   BASE_FONTNAME.  Called when a new Emacs fontset is chosen.  */
+
+void
+xic_set_xfontset (f, base_fontname)
+     struct frame *f;
+     char *base_fontname;
+{
+  XVaNestedList attr;
+  XFontSet xfs;
+
+  xfs = xic_create_xfontset (f, base_fontname);
+
+  attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
+  if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
+    XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+  if (FRAME_XIC_STYLE (f) & XIMStatusArea)
+    XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
+  XFree (attr);
+  
+  if (FRAME_XIC_FONTSET (f))
+    XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+  FRAME_XIC_FONTSET (f) = xfs;
+}
+
+#endif /* HAVE_X_I18N */
+
+
 \f
 #ifdef USE_X_TOOLKIT
 
@@ -3124,7 +3362,6 @@ x_window (f, window_prompting, minibuffer_only)
   XClassHint class_hints;
   XSetWindowAttributes attributes;
   unsigned long attribute_mask;
-
   Widget shell_widget;
   Widget pane_widget;
   Widget frame_widget;
@@ -3150,6 +3387,9 @@ x_window (f, window_prompting, minibuffer_only)
   XtSetArg (al[ac], XtNinput, 1); ac++;
   XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
   XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
   shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
                                   applicationShellWidgetClass,
                                   FRAME_X_DISPLAY (f), al, ac);
@@ -3165,6 +3405,11 @@ x_window (f, window_prompting, minibuffer_only)
                                  (lw_callback) NULL,
                                  (lw_callback) NULL);
 
+  ac = 0;
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
+  XtSetValues (pane_widget, al, ac);
   f->output_data.x->column_widget = pane_widget;
 
   /* mappedWhenManaged to false tells to the paned window to not map/unmap 
@@ -3176,9 +3421,11 @@ x_window (f, window_prompting, minibuffer_only)
   XtSetArg (al[ac], XtNallowResize, 1); ac++;
   XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
   XtSetArg (al[ac], XtNemacsFrame, f); ac++;
-  frame_widget = XtCreateWidget (f->namebuf,
-                                 emacsFrameClass,
-                                 pane_widget, al, ac);
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
+  frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
+                                al, ac);
  
   f->output_data.x->edit_widget = frame_widget;
  
@@ -3266,7 +3513,11 @@ x_window (f, window_prompting, minibuffer_only)
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
   class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
   XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
-  x_create_im (f);
+
+#ifdef HAVE_X_I18N
+  FRAME_XIC (f) = NULL;
+  create_frame_xic (f);
+#endif
 
   f->output_data.x->wm_hints.input = True;
   f->output_data.x->wm_hints.flags |= InputHint;
@@ -3288,8 +3539,19 @@ x_window (f, window_prompting, minibuffer_only)
                   XA_ATOM, 32, PropModeAppend,
                   (unsigned char*) NULL, 0);
 
- /* Make all the standard events reach the Emacs frame.  */
 /* Make all the standard events reach the Emacs frame.  */
   attributes.event_mask = STANDARD_EVENT_SET;
+
+#ifdef HAVE_X_I18N
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+    }
+#endif /* HAVE_X_I18N */
+  
   attribute_mask = CWEventMask;
   XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
                           attribute_mask, &attributes);
@@ -3339,11 +3601,9 @@ x_window (f)
   attributes.backing_store = NotUseful;
   attributes.save_under = True;
   attributes.event_mask = STANDARD_EVENT_SET;
-  attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity
-#if 0
-                   | CWBackingStore | CWSaveUnder
-#endif
-                   | CWEventMask);
+  attributes.colormap = FRAME_X_COLORMAP (f);
+  attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
+                   | CWColormap);
 
   BLOCK_INPUT;
   FRAME_X_WINDOW (f)
@@ -3357,7 +3617,21 @@ x_window (f)
                     InputOutput, /* class */
                     FRAME_X_DISPLAY_INFO (f)->visual,
                     attribute_mask, &attributes);
-  x_create_im (f);
+
+#ifdef HAVE_X_I18N
+  create_frame_xic (f);
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+      attribute_mask = CWEventMask;
+      XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                              attribute_mask, &attributes);
+    }
+#endif /* HAVE_X_I18N */
+  
   validate_x_resource_name ();
 
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
@@ -3633,6 +3907,29 @@ This function is an internal primitive--use `make-frame' instead.")
   FRAME_KBOARD (f) = kb;
 #endif
 
+  /* These colors will be set anyway later, but it's important
+     to get the color reference counts right, so initialize them!  */
+  {
+    Lisp_Object black;
+    struct gcpro gcpro1;
+    
+    black = build_string ("black");
+    GCPRO1 (black);
+    f->output_data.x->foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->background_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->border_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->mouse_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    UNGCPRO;
+  }
+
   /* Specify the parent under which to make this X window.  */
 
   if (!NILP (parent))
@@ -5161,71 +5458,145 @@ See the documentation of `x-rebind-key' for more information.")
 }
 #endif /* HAVE_X11 */
 #endif /* 0 */
+
 \f
+/************************************************************************
+                             X Displays
+ ************************************************************************/
+
+\f
+/* Mapping visual names to visuals.  */
+
+static struct visual_class
+{
+  char *name;
+  int class;
+}
+visual_classes[] =
+{
+  {"StaticGray",       StaticGray},
+  {"GrayScale",                GrayScale},
+  {"StaticColor",      StaticColor},
+  {"PseudoColor",      PseudoColor},
+  {"TrueColor",                TrueColor},
+  {"DirectColor",      DirectColor},
+  NULL
+};
+
+
 #ifndef HAVE_XSCREENNUMBEROFSCREEN
+
+/* Value is the screen number of screen SCR.  This is a substitute for
+   the X function with the same name when that doesn't exist.  */
+
 int
 XScreenNumberOfScreen (scr)
     register Screen *scr;
 {
-  register Display *dpy;
-  register Screen *dpyscr;
-  register int i;
-
-  dpy = scr->display;
-  dpyscr = dpy->screens;
+  Display *dpy = scr->display;
+  int i;
 
-  for (i = 0; i < dpy->nscreens; i++, dpyscr++)
-    if (scr == dpyscr)
-      return i;
+  for (i = 0; i < dpy->nscreens; ++i)
+    if (scr == dpy->screens[i])
+      break;
 
-  return -1;
+  return i;
 }
+
 #endif /* not HAVE_XSCREENNUMBEROFSCREEN */
 
-Visual *
-select_visual (dpy, screen, depth)
-     Display *dpy;
-     Screen *screen;
-     unsigned int *depth;
-{
-  Visual *v;
-  XVisualInfo *vinfo, vinfo_template;
-  int n_visuals;
 
-  v = DefaultVisualOfScreen (screen);
+/* Select the visual that should be used on display DPYINFO.  Set
+   members of DPYINFO appropriately.  Called from x_term_init.  */
 
-#ifdef HAVE_X11R4
-  vinfo_template.visualid = XVisualIDFromVisual (v);
-#else
-  vinfo_template.visualid = v->visualid;
-#endif
+void
+select_visual (dpyinfo)
+     struct x_display_info *dpyinfo;
+{
+  Display *dpy = dpyinfo->display;
+  Screen *screen = dpyinfo->screen;
+  Lisp_Object value;
 
-  vinfo_template.screen = XScreenNumberOfScreen (screen);
+  /* See if a visual is specified.  */
+  value = display_x_get_resource (dpyinfo,
+                                 build_string ("visualClass"),
+                                 build_string ("VisualClass"),
+                                 Qnil, Qnil);
+  if (STRINGP (value))
+    {
+      /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
+        of `PseudoColor', `TrueColor' etc. and DEPTH is the color
+        depth, a decimal number.  NAME is compared with case ignored.  */
+      char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
+      char *dash;
+      int i, class = -1;
+      XVisualInfo vinfo;
+
+      strcpy (s, XSTRING (value)->data);
+      dash = index (s, '-');
+      if (dash)
+       {
+         dpyinfo->n_planes = atoi (dash + 1);
+         *dash = '\0';
+       }
+      else
+       /* We won't find a matching visual with depth 0, so that
+          an error will be printed below.  */
+       dpyinfo->n_planes = 0;
 
-  vinfo = XGetVisualInfo (dpy,
-                         VisualIDMask | VisualScreenMask, &vinfo_template,
-                         &n_visuals);
-  if (n_visuals != 1)
-    fatal ("Can't get proper X visual info");
+      /* Determine the visual class.  */
+      for (i = 0; visual_classes[i].name; ++i)
+       if (xstricmp (s, visual_classes[i].name) == 0)
+         {
+           class = visual_classes[i].class;
+           break;
+         }
 
-  if ((1 << vinfo->depth) == vinfo->colormap_size)
-    *depth = vinfo->depth;
+      /* Look up a matching visual for the specified class.  */
+      if (class == -1
+         || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
+                               dpyinfo->n_planes, class, &vinfo))
+       fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
+      
+      dpyinfo->visual = vinfo.visual;
+    }
   else
     {
-      int i = 0;
-      int n = vinfo->colormap_size - 1;
-      while (n)
+      int n_visuals;
+      XVisualInfo *vinfo, vinfo_template;
+      
+      dpyinfo->visual = DefaultVisualOfScreen (screen);
+
+#ifdef HAVE_X11R4
+      vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
+#else
+      vinfo_template.visualid = dpyinfo->visual->visualid;
+#endif
+      vinfo_template.screen = XScreenNumberOfScreen (screen);
+      vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
+                             &vinfo_template, &n_visuals);
+      if (n_visuals != 1)
+       fatal ("Can't get proper X visual info");
+
+      if ((1 << vinfo->depth) == vinfo->colormap_size)
+       dpyinfo->n_planes = vinfo->depth;
+      else
        {
-         n = n >> 1;
-         i++;
+         int i = 0;
+         int n = vinfo->colormap_size - 1;
+         while (n)
+           {
+             n = n >> 1;
+             i++;
+           }
+         dpyinfo->n_planes = i;
        }
-      *depth = i;
-    }
 
-  XFree ((char *) vinfo);
-  return v;
+      XFree ((char *) vinfo);
+    }
 }
 
+
 /* Return the X display structure for the display named NAME.
    Open a new connection if necessary.  */
 
@@ -5268,6 +5639,7 @@ x_display_info_for_name (name)
   return dpyinfo;
 }
 
+
 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
        1, 3, 0, "Open a connection to an X server.\n\
 DISPLAY is the name of the display to connect to.\n\
@@ -5429,8 +5801,9 @@ Lisp_Object Qxbm;
 
 /* Keywords.  */
 
-Lisp_Object QCtype, QCdata, QCascent, QCmargin, QCrelief;
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
+extern Lisp_Object QCdata;
+Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCindex;
 
@@ -5832,21 +6205,9 @@ x_clear_image (f, img)
       
   if (img->ncolors)
     {
-      int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
-      
-      /* If display has an immutable color map, freeing colors is not
-        necessary and some servers don't allow it.  So don't do it.  */
-      if (class != StaticColor
-         && class != StaticGray
-         && class != TrueColor)
-       {
-         Colormap cmap;
-         BLOCK_INPUT;
-         cmap = DefaultColormapOfScreen (FRAME_X_DISPLAY_INFO (f)->screen);
-         XFreeColors (FRAME_X_DISPLAY (f), cmap, img->colors,
-                      img->ncolors, 0);
-         UNBLOCK_INPUT;
-       }
+      BLOCK_INPUT;
+      x_free_colors (f, img->colors, img->ncolors);
+      UNBLOCK_INPUT;
       
       xfree (img->colors);
       img->colors = NULL;
@@ -7005,8 +7366,10 @@ xpm_load (f, img)
   /* Configure the XPM lib.  Use the visual of frame F.  Allocate
      close colors.  Return colors allocated.  */
   bzero (&attrs, sizeof attrs);
-  attrs.visual = FRAME_X_DISPLAY_INFO (f)->visual;
+  attrs.visual = FRAME_X_VISUAL (f);
+  attrs.colormap = FRAME_X_COLORMAP (f);
   attrs.valuemask |= XpmVisual;
+  attrs.valuemask |= XpmColormap;
   attrs.valuemask |= XpmReturnAllocPixels;
 #ifdef XpmAllocCloseColors
   attrs.alloc_close_colors = 1;
@@ -7231,7 +7594,7 @@ lookup_rgb_color (f, r, g, b)
       color.blue = b;
       
       BLOCK_INPUT;
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       rc = x_alloc_nearest_color (f, cmap, &color);
       UNBLOCK_INPUT;
 
@@ -7278,7 +7641,7 @@ lookup_pixel_color (f, pixel)
 
       BLOCK_INPUT;
       
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       color.pixel = pixel;
       XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
@@ -7396,7 +7759,7 @@ x_laplace (f, img)
      struct frame *f;
      struct image *img;
 {
-  Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+  Colormap cmap = FRAME_X_COLORMAP (f);
   XImage *ximg, *oimg;
   XColor *in[3];
   long *out;
@@ -7534,7 +7897,7 @@ x_build_heuristic_mask (f, img, how)
 
          sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
          
-         cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+         cmap = FRAME_X_COLORMAP (f);
          if (XLookupColor (dpy, cmap, color_name, &exact, &color))
            {
              bg = color.pixel;
@@ -8270,7 +8633,7 @@ png_load (f, img)
          png_color_16 frame_background;
 
          BLOCK_INPUT;
-         cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+         cmap = FRAME_X_COLORMAP (f);
          color.pixel = FRAME_BACKGROUND_PIXEL (f);
          XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
          UNBLOCK_INPUT;
@@ -9671,11 +10034,7 @@ x_kill_gs_process (pixmap, f)
             allocated colors on behalf of us.  So, to get the
             reference counts right, free them once.  */
          if (img->ncolors)
-           {
-             Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
-             XFreeColors (FRAME_X_DISPLAY (f), cmap,
-                          img->colors, img->ncolors, 0);
-           }
+           x_free_colors (f, img->colors, img->ncolors);
 #endif
        }
       else
@@ -9797,48 +10156,114 @@ value.")
                                Busy cursor
  ***********************************************************************/
 
-/* The implementation partly follows a patch from
-   F.Pierresteguy@frcl.bull.fr dated 1994.  */
+/* If non-null, an asynchronous timer that, when it expires, displays
+   a busy cursor on all frames.  */
 
-/* Setting inhibit_busy_cursor to 2 inhibits busy-cursor display until
-   the next X event is read and we enter XTread_socket again.  Setting
-   it to 1 inhibits busy-cursor display for direct commands.  */
+static struct atimer *busy_cursor_atimer;
 
-int inhibit_busy_cursor;
+/* Non-zero means a busy cursor is currently shown.  */
 
-/* Incremented with each call to x-display-busy-cursor.
-   Decremented in x-undisplay-busy-cursor.  */
+static int busy_cursor_shown_p;
 
-static int busy_count;
+/* Number of seconds to wait before displaying a busy cursor.  */
 
+static Lisp_Object Vbusy_cursor_delay;
 
-DEFUN ("x-show-busy-cursor", Fx_show_busy_cursor,
-       Sx_show_busy_cursor, 0, 0, 0,
-  "Show a busy cursor, if not already shown.\n\
-Each call to this function must be matched by a call to\n\
-`x-hide-busy-cursor' to make the busy pointer disappear again.")
-  ()
+/* Default number of seconds to wait before displaying a busy
+   cursor.  */
+
+#define DEFAULT_BUSY_CURSOR_DELAY 1
+
+/* Function prototypes.  */
+
+static void show_busy_cursor P_ ((struct atimer *));
+static void hide_busy_cursor P_ ((void));
+
+
+/* Cancel a currently active busy-cursor timer, and start a new one.  */
+
+void
+start_busy_cursor ()
 {
-  ++busy_count;
-  if (busy_count == 1)
+  EMACS_TIME delay;
+  int secs, usecs = 0;
+  
+  cancel_busy_cursor ();
+
+  if (INTEGERP (Vbusy_cursor_delay)
+      && XINT (Vbusy_cursor_delay) > 0)
+    secs = XFASTINT (Vbusy_cursor_delay);
+  else if (FLOATP (Vbusy_cursor_delay)
+          && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
     {
-      Lisp_Object rest, frame;
+      Lisp_Object tem;
+      tem = Ftruncate (Vbusy_cursor_delay, Qnil);
+      secs = XFASTINT (tem);
+      usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
+    }
+  else
+    secs = DEFAULT_BUSY_CURSOR_DELAY;
+  
+  EMACS_SET_SECS_USECS (delay, secs, usecs);
+  busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
+                                    show_busy_cursor, NULL);
+}
 
+
+/* Cancel the busy cursor timer if active, hide a busy cursor if
+   shown.  */
+
+void
+cancel_busy_cursor ()
+{
+  if (busy_cursor_atimer)
+    {
+      cancel_atimer (busy_cursor_atimer);
+      busy_cursor_atimer = NULL;
+    }
+  
+  if (busy_cursor_shown_p)
+    hide_busy_cursor ();
+}
+
+
+/* Timer function of busy_cursor_atimer.  TIMER is equal to
+   busy_cursor_atimer.
+
+   Display a busy cursor on all frames by mapping the frames'
+   busy_window.  Set the busy_p flag in the frames' output_data.x
+   structure to indicate that a busy cursor is shown on the
+   frames.  */
+
+static void
+show_busy_cursor (timer)
+     struct atimer *timer;
+{
+  /* The timer implementation will cancel this timer automatically
+     after this function has run.  Set busy_cursor_atimer to null
+     so that we know the timer doesn't have to be canceled.  */
+  busy_cursor_atimer = NULL;
+
+  if (!busy_cursor_shown_p)
+    {
+      Lisp_Object rest, frame;
+  
+      BLOCK_INPUT;
+  
       FOR_EACH_FRAME (rest, frame)
        if (FRAME_X_P (XFRAME (frame)))
          {
            struct frame *f = XFRAME (frame);
-           
-           BLOCK_INPUT;
+       
            f->output_data.x->busy_p = 1;
-           
+       
            if (!f->output_data.x->busy_window)
              {
                unsigned long mask = CWCursor;
                XSetWindowAttributes attrs;
-
+           
                attrs.cursor = f->output_data.x->busy_cursor;
-               
+           
                f->output_data.x->busy_window
                  = XCreateWindow (FRAME_X_DISPLAY (f),
                                   FRAME_OUTER_WINDOW (f),
@@ -9847,58 +10272,46 @@ Each call to this function must be matched by a call to\n\
                                   CopyFromParent,
                                   mask, &attrs);
              }
-
+       
            XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-           UNBLOCK_INPUT;
+           XFlush (FRAME_X_DISPLAY (f));
          }
-    }
 
-  return Qnil;
+      busy_cursor_shown_p = 1;
+      UNBLOCK_INPUT;
+    }
 }
 
 
-DEFUN ("x-hide-busy-cursor", Fx_hide_busy_cursor,
-       Sx_hide_busy_cursor, 0, 1, 0,
-  "Hide a busy-cursor.\n\
-A busy-cursor will actually be undisplayed when a matching\n\
-`x-hide-busy-cursor' is called for each `x-show-busy-cursor'\n\
-issued.  FORCE non-nil means hide the busy-cursor forcibly,\n\
-not counting calls.")
-  (force)
-     Lisp_Object force;
-{
-  Lisp_Object rest, frame;
-
-  if (busy_count == 0)
-    return Qnil;
-
-  if (!NILP (force) && busy_count != 0)
-    busy_count = 1;
-
-  --busy_count;
-  if (busy_count != 0)
-    return Qnil;
+/* Hide the busy cursor on all frames, if it is currently shown.  */
 
-  FOR_EACH_FRAME (rest, frame)
+static void
+hide_busy_cursor ()
+{
+  if (busy_cursor_shown_p)
     {
-      struct frame *f = XFRAME (frame);
-      
-      if (FRAME_X_P (f)
-         /* Watch out for newly created frames.  */
-         && f->output_data.x->busy_window)
+      Lisp_Object rest, frame;
+
+      BLOCK_INPUT;
+      FOR_EACH_FRAME (rest, frame)
        {
-         
-         BLOCK_INPUT;
-         XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-         /* Sync here because XTread_socket looks at the busy_p flag
-            that is reset to zero below.  */
-         XSync (FRAME_X_DISPLAY (f), False);
-         UNBLOCK_INPUT;
-         f->output_data.x->busy_p = 0;
+         struct frame *f = XFRAME (frame);
+      
+         if (FRAME_X_P (f)
+             /* Watch out for newly created frames.  */
+             && f->output_data.x->busy_window)
+           {
+             XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
+             /* Sync here because XTread_socket looks at the busy_p flag
+                that is reset to zero below.  */
+             XSync (FRAME_X_DISPLAY (f), False);
+             f->output_data.x->busy_p = 0;
+           }
        }
-    }
 
-  return Qnil;
+      busy_cursor_shown_p = 0;
+      UNBLOCK_INPUT;
+    }
 }
 
 
@@ -10101,8 +10514,8 @@ x_create_tip_frame (dpyinfo, parms)
     
     BLOCK_INPUT;
     mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
-    /* Window managers looks at the override-redirect flag to
-       determine whether or net to give windows a decoration (Xlib
+    /* Window managers look at the override-redirect flag to determine
+       whether or net to give windows a decoration (Xlib spec, chapter
        3.2.8).  */
     attrs.override_redirect = True;
     attrs.save_under = True;
@@ -10685,6 +11098,11 @@ or when you set the mouse color.");
     "Non-zero means Emacs displays a busy cursor on window systems.");
   display_busy_cursor_p = 1;
   
+  DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
+     "*Seconds to wait before displaying a busy-cursor.\n\
+Value must be an integer or float.");
+  Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
+
 #if 0 /* This doesn't really do anything.  */
   DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
              "The shape of the pointer when over the mode line.\n\
@@ -10813,8 +11231,6 @@ Each element of the list is a symbol for a supported image type.");
   staticpro (&QCheuristic_mask);
   QCcolor_symbols = intern (":color-symbols");
   staticpro (&QCcolor_symbols);
-  QCdata = intern (":data");
-  staticpro (&QCdata);
   QCascent = intern (":ascent");
   staticpro (&QCascent);
   QCmargin = intern (":margin");
@@ -10868,11 +11284,8 @@ Each element of the list is a symbol for a supported image type.");
   defsubr (&Slookup_image);
 #endif
 
-  /* Busy-cursor.  */
-  defsubr (&Sx_show_busy_cursor);
-  defsubr (&Sx_hide_busy_cursor);
-  busy_count = 0;
-  inhibit_busy_cursor = 0;
+  busy_cursor_atimer = NULL;
+  busy_cursor_shown_p = 0;
 
   defsubr (&Sx_show_tip);
   defsubr (&Sx_hide_tip);