Include frame.h unconditionally.
[bpt/emacs.git] / src / xfaces.c
index 2a466e6..bb746bb 100644 (file)
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* This is derived from work by Lucid (some parts very loosely so).  */
 
@@ -25,17 +26,24 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <config.h>
 #include "lisp.h"
 
+#include "charset.h"
+
+#include "frame.h"
+
+/* The number of face-id's in use (same for all frames).  */
+static int next_face_id;
+
 #ifdef HAVE_FACES
 
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
+#include "fontset.h"
 #endif
 #ifdef MSDOS
 #include "dosfns.h"
 #endif
 #include "buffer.h"
 #include "dispextern.h"
-#include "frame.h"
 #include "blockinput.h"
 #include "window.h"
 #include "intervals.h"
@@ -75,7 +83,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        ID is the face ID, an integer used internally by the C code to identify
            the face,
        FONT, FOREGROUND, and BACKGROUND are strings naming the fonts and colors
-           to use with the face,
+           to use with the face, FONT may name fontsets,
        BACKGROUND-PIXMAP is the name of an x bitmap filename, which we don't
            use right now, and
        UNDERLINE-P is non-nil if the face should be underlined.
@@ -87,15 +95,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    (assq FACE-NAME global-face-data) returns a vector describing the
    global parameters for that face.
 
-   Let PARAM-FACE be FRAME->display.x->param_faces[Faref (FACE-VECTOR, 2)].
+   Let PARAM-FACE be FRAME->output_data.x->param_faces[Faref (FACE-VECTOR, 2)].
    PARAM_FACE is a struct face whose members are the Xlib analogues of
    the parameters in FACE-VECTOR.  If an element of FACE-VECTOR is
    nil, then the corresponding member of PARAM_FACE is FACE_DEFAULT.
    These faces are called "parameter faces", because they're the ones
    lisp manipulates to control what gets displayed.  Elements 0 and 1
-   of FRAME->display.x->param_faces are special - they describe the
+   of FRAME->output_data.x->param_faces are special - they describe the
    default and mode line faces.  None of the faces in param_faces have
-   GC's.  (See src/dispextern.h for the definiton of struct face.
+   GC's.  (See src/dispextern.h for the definition of struct face.
    lisp/faces.el maintains the isomorphism between face_alist and
    param_faces.)
 
@@ -104,9 +112,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    properties.  The resulting faces are called "computed faces"; none
    of their members are FACE_DEFAULT; they are completely specified.
    They then call intern_compute_face to search
-   FRAME->display.x->computed_faces for a matching face, add one if
+   FRAME->output_data.x->computed_faces for a matching face, add one if
    none is found, and return the index into
-   FRAME->display.x->computed_faces.  FRAME's glyph matrices use these
+   FRAME->output_data.x->computed_faces.  FRAME's glyph matrices use these
    indices to record the faces of the matrix characters, and the X
    display hooks consult compute_faces to decide how to display these
    characters.  Elements 0 and 1 of computed_faces always describe the
@@ -121,6 +129,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    This is done from time to time so that we don't hold on to
    lots of GCs that are no longer needed.
 
+   If a computed face has 0 as its font,
+   it is unused, and can be reused by new_computed_face.
+
    Constraints:
 
    Symbols naming faces must have associations on all frames; for any
@@ -144,11 +155,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 \f
 /* Definitions and declarations.  */
 
-/* The number of face-id's in use (same for all frames).  */
-int next_face_id;
-
 /* The number of the face to use to indicate the region.  */
-int region_face;
+static int region_face;
 
 /* This is what appears in a slot in a face to signify that the face
    does not specify that display aspect.  */
@@ -174,6 +182,7 @@ allocate_face ()
   struct face *result = (struct face *) xmalloc (sizeof (struct face));
   bzero (result, sizeof (struct face));
   result->font = (XFontStruct *) FACE_DEFAULT;
+  result->fontset = -1;
   result->foreground = FACE_DEFAULT;
   result->background = FACE_DEFAULT;
   result->stipple = FACE_DEFAULT;
@@ -188,6 +197,7 @@ copy_face (face)
   struct face *result = allocate_face ();
 
   result->font = face->font;
+  result->fontset = face->fontset;
   result->foreground = face->foreground;
   result->background = face->background;
   result->stipple = face->stipple;
@@ -203,6 +213,7 @@ face_eql (face1, face2)
      struct face *face1, *face2;
 {
   return (   face1->font       == face2->font
+         && face1->fontset == face2->fontset
          && face1->foreground == face2->foreground
          && face1->background == face2->background
          && face1->stipple    == face2->stipple
@@ -231,17 +242,17 @@ intern_face (f, face)
   if (face->foreground != FACE_DEFAULT)
     xgcv.foreground = face->foreground;
   else
-    xgcv.foreground = f->display.x->foreground_pixel;
+    xgcv.foreground = f->output_data.x->foreground_pixel;
 
   if (face->background != FACE_DEFAULT)
     xgcv.background = face->background;
   else
-    xgcv.background = f->display.x->background_pixel;
+    xgcv.background = f->output_data.x->background_pixel;
 
-  if (face->font && (int) face->font != FACE_DEFAULT)
+  if (face->font && face->font != (XFontStruct *) FACE_DEFAULT)
     xgcv.font = face->font->fid;
   else
-    xgcv.font = f->display.x->font->fid;
+    xgcv.font = f->output_data.x->font->fid;
 
   xgcv.graphics_exposures = 0;
 
@@ -257,6 +268,10 @@ intern_face (f, face)
                  mask, &xgcv);
 
   face->gc = gc;
+  /* We used the following GC for all non-ASCII characters by changing
+     only GCfont each time.  */
+  face->non_ascii_gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                                 mask, &xgcv);
 
   UNBLOCK_INPUT;
 
@@ -286,7 +301,10 @@ clear_face_cache ()
            {
              struct face *face = FRAME_COMPUTED_FACES (f) [i];
              if (face->gc)
-               XFreeGC (dpy, face->gc);
+               {
+                 XFreeGC (dpy, face->gc);
+                 XFreeGC (dpy, face->non_ascii_gc);
+               }
              face->gc = 0;
            }
        }
@@ -327,10 +345,29 @@ unload_font (f, font)
      struct frame *f;
      XFontStruct *font;
 {
+  int len = FRAME_N_COMPUTED_FACES (f);
+  int i;
+
   if (!font || font == ((XFontStruct *) FACE_DEFAULT))
     return;
 
   BLOCK_INPUT;
+  /* Invalidate any computed faces which use this font,
+     and free their GC's if they have any.  */
+  for (i = 2; i < len; i++)
+    {
+      struct face *face = FRAME_COMPUTED_FACES (f)[i];
+      if (face->font == font)
+       {
+         Display *dpy = FRAME_X_DISPLAY (f);
+         if (face->gc)
+           XFreeGC (dpy, face->gc);
+         face->gc = 0;
+         /* This marks the computed face as available to reuse.  */
+         face->font = 0;
+       }
+    }
+
   XFreeFont (FRAME_X_DISPLAY (f), font);
   UNBLOCK_INPUT;
 }
@@ -340,29 +377,19 @@ load_color (f, name)
      struct frame *f;
      Lisp_Object name;
 {
-  Display *dpy = FRAME_X_DISPLAY (f);
-  Colormap cmap;
   XColor color;
   int result;
 
   if (NILP (name))
     return FACE_DEFAULT;
 
-  cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy));
-
   CHECK_STRING (name, 0);
-  BLOCK_INPUT;
-  result = XParseColor (dpy, cmap, (char *) XSTRING (name)->data, &color);
-  UNBLOCK_INPUT;
+  /* if the colormap is full, defined_color will return a best match
+     to the values in an an existing cell. */
+  result = defined_color(f, (char *) XSTRING (name)->data, &color, 1);
   if (! result)
     Fsignal (Qerror, Fcons (build_string ("undefined color"),
                            Fcons (name, Qnil)));
-  BLOCK_INPUT;
-  result = XAllocColor (dpy, cmap, &color);
-  UNBLOCK_INPUT;
-  if (! result)
-    Fsignal (Qerror, Fcons (build_string ("X server cannot allocate color"),
-                           Fcons (name, Qnil)));
   return (unsigned long) color.pixel;
 }
 
@@ -373,37 +400,65 @@ unload_color (f, pixel)
 {
   Colormap cmap;
   Display *dpy = FRAME_X_DISPLAY (f);
+  int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
+
   if (pixel == FACE_DEFAULT
-      || pixel == BLACK_PIX_DEFAULT
-      || pixel == WHITE_PIX_DEFAULT)
+      || pixel == BLACK_PIX_DEFAULT (f)
+      || pixel == WHITE_PIX_DEFAULT (f))
     return;
   cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy));
-  BLOCK_INPUT;
-  XFreeColors (dpy, cmap, &pixel, 1, 0);
-  UNBLOCK_INPUT;
+  
+  /* 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))
+    {
+      int len = FRAME_N_COMPUTED_FACES (f);
+      int i;
+
+      BLOCK_INPUT;
+      /* Invalidate any computed faces which use this color,
+        and free their GC's if they have any.  */
+      for (i = 2; i < len; i++)
+       {
+         struct face *face = FRAME_COMPUTED_FACES (f)[i];
+         if (face->foreground == pixel
+             || face->background == pixel)
+           {
+             Display *dpy = FRAME_X_DISPLAY (f);
+             if (face->gc)
+               XFreeGC (dpy, face->gc);
+             face->gc = 0;
+             /* This marks the computed face as available to reuse.  */
+             face->font = 0;
+           }
+       }
+
+      XFreeColors (dpy, cmap, &pixel, 1, (unsigned long)0);
+      UNBLOCK_INPUT;
+    }
 }
 
 DEFUN ("pixmap-spec-p", Fpixmap_spec_p, Spixmap_spec_p, 1, 1, 0,
-  "Return t if ARG is a valid pixmap specification.")
-  (arg)
-     Lisp_Object arg;
+  "Return t if OBJECT is a valid pixmap specification.")
+  (object)
+     Lisp_Object object;
 {
   Lisp_Object height, width;
 
-  return ((STRINGP (arg)
-          || (CONSP (arg)
-              && CONSP (Fcdr (arg))
-              && CONSP (Fcdr (Fcdr (arg)))
-              && NILP (Fcdr (Fcdr (Fcdr (arg))))
-              && INTEGERP (width = Fcar (arg))
-              && INTEGERP (height = Fcar (Fcdr (arg)))
-              && STRINGP (Fcar (Fcdr (Fcdr (arg))))
+  return ((STRINGP (object)
+          || (CONSP (object)
+              && CONSP (XCONS (object)->cdr)
+              && CONSP (XCONS (XCONS (object)->cdr)->cdr)
+              && NILP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->cdr)
+              && (width = XCONS (object)->car, INTEGERP (width))
+              && (height = XCONS (XCONS (object)->cdr)->car, INTEGERP (height))
+              && STRINGP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)
               && XINT (width) > 0
               && XINT (height) > 0
               /* The string must have enough bits for width * height.  */
-              && (XINT (width) * XINT (height)
-                  <= (XSTRING (Fcar (Fcdr (Fcdr (arg))))->size
-                      * (INTBITS / sizeof (int))))))
+              && ((XSTRING (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)->size
+                   * (BITS_PER_INT / sizeof (int)))
+                  >= XFASTINT (width) * XFASTINT (height))))
          ? Qt : Qnil);
 }
 
@@ -415,7 +470,7 @@ DEFUN ("pixmap-spec-p", Fpixmap_spec_p, Spixmap_spec_p, 1, 1, 0,
 
 static long
 load_pixmap (f, name, w_ptr, h_ptr)
-     FRAME_PTR *f;
+     FRAME_PTR f;
      Lisp_Object name;
      unsigned int *w_ptr, *h_ptr;
 {
@@ -452,8 +507,8 @@ load_pixmap (f, name, w_ptr, h_ptr)
     }
   UNBLOCK_INPUT;
 
-  if (! bitmap_id)
-    Fsignal (Qerror, Fcons (build_string ("undefined bitmap"),
+  if (bitmap_id < 0)
+    Fsignal (Qerror, Fcons (build_string ("invalid or undefined bitmap"),
                            Fcons (name, Qnil)));
 
   *w_ptr = x_bitmap_width (f, bitmap_id);
@@ -480,14 +535,6 @@ clear_face_cache ()
   /* No action.  */
 }
 
-static void
-build_face (f, face)
-     struct frame *f;
-     struct face *face;
-{
-  face->gc = 1;
-}
-
 #ifdef MSDOS
 unsigned long
 load_color (f, name)
@@ -527,14 +574,13 @@ init_frame_faces (f)
   new_computed_face (f, FRAME_PARAM_FACES (f)[1]);
   recompute_basic_faces (f);
 
-#ifdef MULTI_FRAME
   /* Find another X frame.  */
   {
     Lisp_Object tail, frame, result;
     
     result = Qnil;
     FOR_EACH_FRAME (tail, frame)
-      if (FRAME_X_P (XFRAME (frame))
+      if ((FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame)))
          && XFRAME (frame) != f)
        {
          result = frame;
@@ -556,7 +602,6 @@ init_frame_faces (f)
            ensure_face_ready (f, i);
       }
   }
-#endif /* MULTI_FRAME */
 }
 
 
@@ -576,7 +621,8 @@ free_frame_faces (f)
       struct face *face = FRAME_PARAM_FACES (f) [i];
       if (face)
        {
-         unload_font (f, face->font);
+         if (face->fontset < 0)
+           unload_font (f, face->font);
          unload_color (f, face->foreground);
          unload_color (f, face->background);
          x_destroy_bitmap (f, face->stipple);
@@ -596,7 +642,10 @@ free_frame_faces (f)
       if (face)
        {
          if (face->gc)
-           XFreeGC (dpy, face->gc);
+           {
+             XFreeGC (dpy, face->gc);
+             XFreeGC (dpy, face->non_ascii_gc);
+           }
          xfree (face);
        }
     }
@@ -614,7 +663,19 @@ new_computed_face (f, new_face)
      struct frame *f;
      struct face *new_face;
 {
-  int i = FRAME_N_COMPUTED_FACES (f);
+  int len = FRAME_N_COMPUTED_FACES (f);
+  int i;
+
+  /* Search for an unused computed face in the middle of the table.  */
+  for (i = 0; i < len; i++)
+    {
+      struct face *face = FRAME_COMPUTED_FACES (f)[i];
+      if (face->font == 0)
+       {
+         FRAME_COMPUTED_FACES (f)[i] = copy_face (new_face);
+         return i;
+       }
+    }
 
   if (i >= FRAME_SIZE_COMPUTED_FACES (f))
     {
@@ -709,21 +770,27 @@ frame_update_line_height (f)
      FRAME_PTR f;
 {
   int i;
-  int biggest = FONT_HEIGHT (f->display.x->font);
-
-  for (i = 0; i < f->display.x->n_param_faces; i++)
-    if (f->display.x->param_faces[i] != 0
-       && f->display.x->param_faces[i]->font != (XFontStruct *) FACE_DEFAULT)
+  int fontset = f->output_data.x->fontset;
+  int biggest = (fontset > 0
+                ? FRAME_FONTSET_DATA (f)->fontset_table[fontset]->height
+                : FONT_HEIGHT (f->output_data.x->font));
+
+  for (i = 0; i < f->output_data.x->n_param_faces; i++)
+    if (f->output_data.x->param_faces[i] != 0
+       && f->output_data.x->param_faces[i]->font != (XFontStruct *) FACE_DEFAULT)
       {
-       int height = FONT_HEIGHT (f->display.x->param_faces[i]->font);
+       int height = ((fontset = f->output_data.x->param_faces[i]->fontset) > 0
+                     ? FRAME_FONTSET_DATA (f)->fontset_table[fontset]->height
+                     : FONT_HEIGHT (f->output_data.x->param_faces[i]->font));
+
        if (height > biggest)
          biggest = height;
       }
 
-  if (biggest == f->display.x->line_height)
+  if (biggest == f->output_data.x->line_height)
     return 0;
 
-  f->display.x->line_height = biggest;
+  f->output_data.x->line_height = biggest;
   return 1;
 }
 #endif /* not HAVE_X_WINDOWS */
@@ -740,6 +807,8 @@ merge_faces (from, to)
   if (from->font != (XFontStruct *) FACE_DEFAULT
       && same_size_fonts (from->font, to->font))
     to->font = from->font;
+  if (from->fontset != -1)
+    to->fontset = from->fontset;
   if (from->foreground != FACE_DEFAULT)
     to->foreground = from->foreground;
   if (from->background != FACE_DEFAULT)
@@ -766,6 +835,7 @@ compute_base_face (f, face)
   face->foreground = FRAME_FOREGROUND_PIXEL (f);
   face->background = FRAME_BACKGROUND_PIXEL (f);
   face->font = FRAME_FONT (f);
+  face->fontset = -1;
   face->stipple = 0;
   face->underline = 0;
 }
@@ -884,7 +954,8 @@ compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
     len = 40;
     overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
     
-    noverlays = overlays_at (pos, 0, &overlay_vec, &len, &next_overlay, NULL);
+    noverlays = overlays_at (pos, 0, &overlay_vec, &len,
+                            &next_overlay, (int *) 0);
 
     /* If there are more than 40,
        make enough space for all, and try again.  */
@@ -893,7 +964,7 @@ compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
        len = noverlays;
        overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
        noverlays = overlays_at (pos, 0, &overlay_vec, &len,
-                                &next_overlay, NULL);
+                                &next_overlay, (int *) 0);
       }
 
     if (next_overlay < endpos)
@@ -912,10 +983,13 @@ compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
   if (CONSP (prop))
     {
       /* We have a list of faces, merge them in reverse order */
-      Lisp_Object length = Flength (prop);
-      int len = XINT (length);
+      Lisp_Object length;
+      int len;
       Lisp_Object *faces;
 
+      length = Fsafe_length (prop);
+      len = XFASTINT (length);
+
       /* Put them into an array */
       faces = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
       for (j = 0; j < len; j++)
@@ -949,10 +1023,12 @@ compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
       if (CONSP (prop))
        {
          /* We have a list of faces, merge them in reverse order */
-         Lisp_Object length = Flength (prop);
-         int len = XINT (length);
+         Lisp_Object length;
+         int len;
          Lisp_Object *faces;
-         int i;
+
+         length = Fsafe_length (prop);
+         len = XFASTINT (length);
 
          /* Put them into an array */
          faces = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
@@ -1016,10 +1092,15 @@ recompute_basic_faces (f)
   BLOCK_INPUT;
 
   if (FRAME_DEFAULT_FACE (f)->gc)
-    XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->gc);
+    {
+      XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->gc);
+      XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->non_ascii_gc);
+    }
   if (FRAME_MODE_LINE_FACE (f)->gc)
-    XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->gc);
-
+    {
+      XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->gc);
+      XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->non_ascii_gc);
+    }
   compute_base_face (f, FRAME_DEFAULT_FACE (f));
   compute_base_face (f, FRAME_MODE_LINE_FACE (f));
 
@@ -1036,26 +1117,6 @@ recompute_basic_faces (f)
 \f
 /* Lisp interface. */
 
-DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0,
-       "")
-     (frame)
-     Lisp_Object frame;
-{
-  CHECK_FRAME (frame, 0);
-  return XFRAME (frame)->face_alist;
-}
-
-DEFUN ("set-frame-face-alist", Fset_frame_face_alist, Sset_frame_face_alist,
-       2, 2, 0, "")
-     (frame, value)
-     Lisp_Object frame, value;
-{
-  CHECK_FRAME (frame, 0);
-  XFRAME (frame)->face_alist = value;
-  return value;
-}
-
-
 DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
   "Create face number FACE-ID on all frames.")
   (face_id)
@@ -1070,7 +1131,7 @@ DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
 
   FOR_EACH_FRAME (rest, frame)
     {
-      if (FRAME_X_P (XFRAME (frame)))
+      if (FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame)))
        ensure_face_ready (XFRAME (frame), id);
     }
   return Qnil;
@@ -1097,7 +1158,7 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
   if (id < 0 || id >= next_face_id)
     error ("Face id out of range");
 
-  if (! FRAME_X_P (f))
+  if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
     return Qnil;
 
   ensure_face_ready (f, id);
@@ -1106,12 +1167,42 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
   if (EQ (attr_name, intern ("font")))
     {
 #if defined (MSDOS) && !defined (HAVE_X_WINDOWS)
-      face->font = 0; /* The one and only font.  */
+      /* The one and only font.  Must *not* be zero (which
+        is taken to mean an unused face nowadays).  */
+      face->font = (XFontStruct *)1 ;
 #else
-      XFontStruct *font = load_font (f, attr_value);
-      if (face->font != f->display.x->font)
+      XFontStruct *font;
+      int fontset;
+
+      if (NILP (attr_value))
+       {
+         font = (XFontStruct *) FACE_DEFAULT;
+         fontset = -1;
+       }
+      else
+       {
+         CHECK_STRING (attr_value, 0);
+         fontset = fs_query_fontset (f, XSTRING (attr_value)->data);
+         if (fontset >= 0)
+           {
+             struct font_info *fontp;
+             
+             if (!(fontp = fs_load_font (f, FRAME_X_FONT_TABLE (f),
+                                         CHARSET_ASCII, NULL, fontset)))
+               Fsignal (Qerror,
+                        Fcons (build_string ("ASCII font can't be loaded"),
+                               Fcons (attr_value, Qnil)));
+             font = (XFontStruct *) (fontp->font);
+           }
+         else
+           font = load_font (f, attr_value);
+       }
+
+      if (face->fontset == -1 && face->font != f->output_data.x->font)
        unload_font (f, face->font);
+
       face->font = font;
+      face->fontset = fontset;
       if (frame_update_line_height (f))
        x_set_window_size (f, 0, f->width, f->height);
       /* Must clear cache, since it might contain the font
@@ -1130,9 +1221,6 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
     {
       unsigned long new_color = load_color (f, attr_value);
       unload_color (f, face->background);
-#if defined (MSDOS) && !defined (HAVE_X_WINDOWS)
-      new_color &= ~8;  /* Bright would give blinking characters.  */
-#endif
       face->background = new_color;
       garbaged = 1;
     }
@@ -1163,18 +1251,13 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
      And we must inhibit any Expose events until the redraw is done,
      since they would try to use the invalid display faces.  */
   if (garbaged)
-    SET_FRAME_GARBAGED (f);
+    {
+      SET_FRAME_GARBAGED (f);
+      FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
+    }
 
   return Qnil;
 }
-
-DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
-  0, 0, 0, "")
-  ()
-{
-  return make_number (next_face_id++);
-}
-
 /* Return the face id for name NAME on frame FRAME.
    (It should be the same for all frames,
    but it's as easy to use the "right" frame to look it up
@@ -1195,12 +1278,42 @@ face_name_id_number (f, name)
   CHECK_NUMBER (tem, 0);
   return XINT (tem);
 }
+
+#endif /* HAVE_FACES */
+
+\f
+DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0,
+       "")
+     (frame)
+     Lisp_Object frame;
+{
+  CHECK_FRAME (frame, 0);
+  return XFRAME (frame)->face_alist;
+}
+
+DEFUN ("set-frame-face-alist", Fset_frame_face_alist, Sset_frame_face_alist,
+       2, 2, 0, "")
+     (frame, value)
+     Lisp_Object frame, value;
+{
+  CHECK_FRAME (frame, 0);
+  XFRAME (frame)->face_alist = value;
+  return value;
+}
+
+DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
+  0, 0, 0, "")
+  ()
+{
+  return make_number (next_face_id++);
+}
 \f
 /* Emacs initialization.  */
 
 void
 syms_of_xfaces ()
 {
+#ifdef HAVE_FACES
   Qface = intern ("face");
   staticpro (&Qface);
   Qmouse_face = intern ("mouse-face");
@@ -1213,14 +1326,15 @@ syms_of_xfaces ()
 The region is highlighted with this face\n\
 when Transient Mark mode is enabled and the mark is active.");
 
+  defsubr (&Smake_face_internal);
+  defsubr (&Sset_face_attribute_internal);
+#endif /* HAVE_FACES */
+
 #ifdef HAVE_X_WINDOWS
   defsubr (&Spixmap_spec_p);
 #endif
+
   defsubr (&Sframe_face_alist);
   defsubr (&Sset_frame_face_alist);
-  defsubr (&Smake_face_internal);
-  defsubr (&Sset_face_attribute_internal);
   defsubr (&Sinternal_next_face_id);
 }
-
-#endif /* HAVE_FACES */