]> code.delx.au - gnu-emacs/blobdiff - src/xfaces.c
Remove #definition of HAVE_CLOSEDIR; autoconf figures this out.
[gnu-emacs] / src / xfaces.c
index 643c8de18a55120223965124ab693f66b0ed752f..8a00ece903d0ddc991fa81e72131dff91729c841 100644 (file)
@@ -1,5 +1,5 @@
-/* "Face" primitives
-   Copyright (C) 1992, 1993 Free Software Foundation.
+/* "Face" primitives.
+   Copyright (C) 1993 Free Software Foundation.
 
 This file is part of GNU Emacs.
 
@@ -25,37 +25,119 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "config.h"
 #include "lisp.h"
 
+#ifdef HAVE_X_WINDOWS
+
 #include "xterm.h"
 #include "buffer.h"
 #include "dispextern.h"
 #include "frame.h"
 #include "blockinput.h"
-/* #include "window.h" */
+#include "window.h"
+
+/* Compensate for bug in Xos.h on some systems.  */
+#ifdef XOS_NEEDS_TIME_H
+#include <time.h>
+#define __TIMEVAL__
+#endif
 
+/* These don't seem to be used.  */
+#if 0
 /* Display Context for the icons */ 
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Xmu/Drawing.h>
-#include <X11/Xos.h>
-
-/* We use face structures in two ways:
-   At the frame level, each frame has a vector of faces (FRAME_FACES).
-   Face number 0 is the default face (for normal text).
-   Face number 1 is the mode line face.
-   Higher face numbers have no built-in meaning.
-   The faces in these vectors are called "frame faces".
-
-   Faces number 0 and 1 have graphics contexts.
-   They can be used in the redisplay code directly.
-   Higher numbered frame faces do not have graphics contexts.
+#endif
 
-   There are also "cached faces".  They have graphics contexts.
-   They are kept in a C vector called face_vector.
+#include <X11/Xos.h>
 
-   A "display face" is a face with a graphics context.
-   It is either a frame face number 0 or 1,
-   or a cached face.  */
+\f
+/* An explanation of the face data structures.  */
+
+/* ========================= Face Data Structures =========================
+
+   All lisp code uses symbols as face names.
+
+   Each frame has a face_alist member (with the frame-face-alist and
+   set-frame-face-alist accessors), associating the face names with
+   vectors of the form 
+       [face NAME ID FONT FOREGROUND BACKGROUND BACKGROUND-PIXMAP UNDERLINE-P]
+   where
+       face is the symbol `face',
+       NAME is the symbol with which this vector is associated (a backpointer),
+       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,
+       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.
+   If any of these elements are nil, that allows the frame's parameters to
+   show through.
+   (lisp/faces.el maintains these association lists.)
+
+   The frames' private alists hold the frame-local definitions for the
+   faces.  The lisp variable global-face-data contains the global
+   defaults for faces.  (See lisp/faces.el for this too.)
+
+   In the C code, we also have a `struct face' with the elements
+      `foreground', `background', `font', and `underline',
+   which specify its visual appearance, and elements
+      `gc' and `cached_index';
+   `gc' may be an X GC which has been built for the given display
+   parameters.  Faces with GC's are called `display faces'.  Whether
+   or not a face has a GC depends on what data structure the face is
+   in; we explain these more below.  (See src/dispextern.h.)
+
+   Each frame also has members called `faces' and `n_faces' (with the
+   accessors FRAME_FACES and FRAME_N_FACES), which define an array of
+   struct face pointers, indexed by face ID (element 2 of the
+   vector).  These are called "frame faces".
+      Element 0 is the default face --- the one used for normal text.
+      Element 1 is the modeline face.
+   These faces have their GC's set; the rest do not.
+   If faces[i] is filled in (i.e. non-zero) on one frame, then it must
+   be filled in on all frames.  Code assumes that face ID's can be
+   used on any frame.  (See src/xterm.h.)
+
+   The global variables `face_vector' and `nfaces' define another
+   array of struct face pointers, with their GC's set.  This array
+   acts as a cache of GC's to be used by all frames.  The function
+   `intern_face', passed a struct face *, searches face_vector for a
+   struct face with the same parameters, adds a new one with a GC if
+   it doesn't find one, and returns it.  If you have a `struct face',
+   and you want a GC for it, call intern_face on that struct, and it
+   will return a `struct face *' with its GC set.  The faces in
+   face_vector are called `cached faces.' (See src/xfaces.c.)
+
+   The `GLYPH' data type is an unsigned integer type; the bottom byte
+   is a character code, and the byte above that is a face id.  The
+   `struct frame_glyphs' structure, used to describe frames' current
+   or desired contents, is essentially a matrix of GLYPHs; the face
+   ID's in a struct frame_glyphs are indices into FRAME_FACES.  (See
+   src/dispextern.h.)
+
+   Some subtleties:
+   
+   Since face_vector is just a cache --- there are no pointers into it
+   from the rest of the code, and everyone accesses it through
+   intern_face --- we could just free its GC's and throw the whole
+   thing away without breaking anything.  This gives us a simple way
+   to garbage-collect old GC's nobody's using any more - we can just
+   purge face_vector, and then let subsequent calls to intern_face
+   refill it as needed.  The function clear_face_vector performs this
+   purge.
+
+   We're often applying intern_face to faces in frames' local arrays -
+   for example, we do this while sending GLYPHs from a struct
+   frame_glyphs to X during redisplay.  It would be nice to avoid
+   searching all of face_vector every time we intern a frame's face.
+   So, when intern_face finds a match for FACE in face_vector, it
+   stores the index of the match in FACE's cached_index member, and
+   checks there first next time.  */
    
+\f
+/* Definitions and declarations.  */
+
 /* A table of display faces.  */
 struct face **face_vector;
 /* The length in use of the table.  */
@@ -66,18 +148,37 @@ int nfaces_allocated;
 /* 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;
+
+/* This is what appears in a slot in a face to signify that the face
+   does not specify that display aspect.  */
 #define FACE_DEFAULT (~0)
 
 Lisp_Object Qface, Qwindow, Qpriority;
 
-static struct face *allocate_face ();
 static void build_face ();
-static int sort_overlays ();
-static struct face *get_display_face ();
-static Lisp_Object face_name_id_number ();
+int face_name_id_number ();
+
+struct face *intern_face ();
+static void ensure_face_ready ();
 \f
-/* Make a new face that's a copy of an existing one.  */
+/* Allocating, copying, and comparing struct faces.  */
 
+/* Allocate a new face */
+static struct face *
+allocate_face ()
+{
+  struct face *result = (struct face *) xmalloc (sizeof (struct face));
+  bzero (result, sizeof (struct face));
+  result->font = (XFontStruct *) FACE_DEFAULT;
+  result->foreground = FACE_DEFAULT;
+  result->background = FACE_DEFAULT;
+  result->stipple = FACE_DEFAULT;
+  return result;
+}
+
+/* Make a new face that's a copy of an existing one.  */
 static struct face *
 copy_face (face)
      struct face *face;
@@ -97,18 +198,18 @@ static int
 face_eql (face1, face2)
      struct face *face1, *face2;
 {
-  return (face1->font == face2->font
+  return (   face1->font       == face2->font
          && face1->foreground == face2->foreground
          && face1->background == face2->background
-         && face1->stipple == face2->stipple
-         && face1->underline == face2->underline);
+         && face1->stipple    == face2->stipple
+         && face1->underline  == face2->underline);
 }
+\f
+/* Interning faces in the `face_vector' cache, and clearing that cache.  */
 
 /* Return the unique display face corresponding to the user-level face FACE.
-
    If there isn't one, make one, and find a slot in the face_vector to
    put it in.  */
-
 static struct face *
 get_cached_face (f, face)
      struct frame *f;
@@ -117,6 +218,13 @@ get_cached_face (f, face)
   int i, empty = -1;
   struct face *result;
 
+  /* Perhaps FACE->cached_index is valid; this could happen if FACE is
+     in a frame's face list.  */
+  if (face->cached_index >= 0
+      && face->cached_index < nfaces
+      && face_eql (face_vector[face->cached_index], face))
+    return face_vector[face->cached_index];
+
   /* Look for an existing display face that does the job.
      Also find an empty slot if any.   */
   for (i = 0; i < nfaces; i++)
@@ -150,6 +258,38 @@ get_cached_face (f, face)
   return result;
 }
 
+/* Given a frame face, return an equivalent display face
+   (one which has a graphics context).  */
+
+struct face *
+intern_face (f, face)
+     struct frame *f;
+     struct face *face;
+{
+  /* If it's equivalent to the default face, use that.  */
+  if (face_eql (face, FRAME_DEFAULT_FACE (f)))
+    {
+      if (!FRAME_DEFAULT_FACE (f)->gc)
+       build_face (f, FRAME_DEFAULT_FACE (f));
+      return FRAME_DEFAULT_FACE (f);
+    }
+  
+  /* If it's equivalent to the mode line face, use that.  */
+  if (face_eql (face, FRAME_MODE_LINE_FACE (f)))
+    {
+      if (!FRAME_MODE_LINE_FACE (f)->gc)
+       build_face (f, FRAME_MODE_LINE_FACE (f));
+      return FRAME_MODE_LINE_FACE (f);
+    }
+
+  /* If it's not one of the frame's default faces, it shouldn't have a GC.  */
+  if (face->gc)
+    abort ();
+  
+  /* Get a specialized display face.  */
+  return get_cached_face (f, face);
+}
+
 /* Clear out face_vector and start anew.
    This should be done from time to time just to avoid
    keeping too many graphics contexts in face_vector
@@ -176,52 +316,314 @@ clear_face_vector ()
   UNBLOCK_INPUT;
 }
 \f
+/* Allocating and freeing X resources for display faces.  */
+
 /* Make a graphics context for face FACE, which is on frame F,
    if that can be done.  */
-
 static void
 build_face (f, face)
-     struct framef;
-     struct faceface;
+     struct frame *f;
+     struct face *face;
 {
   GC gc;
   XGCValues xgcv;
   unsigned long mask;
 
+  BLOCK_INPUT;
+
   if (face->foreground != FACE_DEFAULT)
     xgcv.foreground = face->foreground;
   else
-    xgcv. foreground = f->display.x->foreground_pixel;
+    xgcv.foreground = f->display.x->foreground_pixel;
+
   if (face->background != FACE_DEFAULT)
     xgcv.background = face->background;
   else
-    xgcv. background = f->display.x->background_pixel;
+    xgcv.background = f->display.x->background_pixel;
+
   if (face->font && (int) face->font != FACE_DEFAULT)
     xgcv.font = face->font->fid;
   else
     xgcv.font = f->display.x->font->fid;
+
   xgcv.graphics_exposures = 0;
+
   mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
   gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
                  mask, &xgcv);
+
 #if 0
   if (face->stipple && face->stipple != FACE_DEFAULT)
     XSetStipple (x_current_display, gc, face->stipple);
 #endif
+
   face->gc = gc;
+
+  UNBLOCK_INPUT;
+}
+
+/* Allocating, freeing, and duplicating fonts, colors, and pixmaps.  */
+
+static XFontStruct *
+load_font (f, name)
+     struct frame *f;
+     Lisp_Object name;
+{
+  XFontStruct *font;
+
+  if (NILP (name))
+    return (XFontStruct *) FACE_DEFAULT;
+
+  CHECK_STRING (name, 0);
+  BLOCK_INPUT;
+  font = XLoadQueryFont (x_current_display, (char *) XSTRING (name)->data);
+  UNBLOCK_INPUT;
+
+  if (! font)
+    Fsignal (Qerror, Fcons (build_string ("undefined font"),
+                           Fcons (name, Qnil)));
+  return font;
+}
+
+static void
+unload_font (f, font)
+     struct frame *f;
+     XFontStruct *font;
+{
+  if (!font || font == ((XFontStruct *) FACE_DEFAULT))
+    return;
+
+  BLOCK_INPUT;
+  XFreeFont (x_current_display, font);
+  UNBLOCK_INPUT;
+}
+
+static unsigned long
+load_color (f, name)
+     struct frame *f;
+     Lisp_Object name;
+{
+  Display *dpy = x_current_display;
+  Colormap cmap;
+  XColor color;
+  int result;
+
+  if (NILP (name))
+    return FACE_DEFAULT;
+
+  cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
+
+  CHECK_STRING (name, 0);
+  BLOCK_INPUT;
+  result = XParseColor (dpy, cmap, (char *) XSTRING (name)->data, &color);
+  UNBLOCK_INPUT;
+  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;
+}
+
+static void
+unload_color (f, pixel)
+     struct frame *f;
+     unsigned long pixel;
+{
+  /* Since faces get built by copying parameters from other faces, the
+     allocation counts for the colors get all screwed up.  I don't see
+     any solution that will take less than 10 minutes, and it's better
+     to have a color leak than a crash, so I'm just dyking this out.
+     This isn't really a color leak, anyway - if we ask for it again,
+     we'll get the same pixel.  */
+#if 0
+  Colormap cmap;
+  Display *dpy = x_current_display;
+  if (pixel == FACE_DEFAULT
+      || pixel == BLACK_PIX_DEFAULT
+      || pixel == WHITE_PIX_DEFAULT)
+    return;
+  cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
+  BLOCK_INPUT;
+  XFreeColors (dpy, cmap, &pixel, 1, 0);
+  UNBLOCK_INPUT;
+#endif
 }
 \f
+/* Initializing face arrays for frames. */
+
+void
+init_frame_faces (f)
+     FRAME_PTR f;
+{
+  ensure_face_ready (f, 0);
+  ensure_face_ready (f, 1);
+
+  recompute_basic_faces (f);
+
+  /* Find another X frame.  */
+  {
+    Lisp_Object tail, frame, result;
+    
+    result = Qnil;
+    FOR_EACH_FRAME (tail, frame)
+      if (FRAME_X_P (XFRAME (frame))
+         && XFRAME (frame) != f)
+       {
+         result = frame;
+         break;
+       }
+
+    /* If we didn't find any X frames other than f, then we don't need
+       any faces other than 0 and 1, so we're okay.  Otherwise, make
+       sure that all faces valid on the selected frame are also valid
+       on this new frame.  */
+    if (FRAMEP (result))
+      {
+       int i;
+       int n_faces = XFRAME (result)->display.x->n_faces;
+       struct face **faces = XFRAME (result)->display.x->faces;
+
+       for (i = 2; i < n_faces; i++)
+         if (faces[i])
+           ensure_face_ready (f, i);
+      }
+  }
+}
+
+
+/* Called from Fdelete_frame.  */
+void
+free_frame_faces (f)
+     struct frame *f;
+{
+  Display *dpy = x_current_display;
+  int i;
+
+  BLOCK_INPUT;
+
+  for (i = 0; i < FRAME_N_FACES (f); i++)
+    {
+      struct face *face = FRAME_FACES (f) [i];
+      if (face)
+       {
+         if (face->gc)
+           XFreeGC (dpy, face->gc);
+         if (! face->copy)
+           {
+             unload_font (f, face->font);
+             unload_color (f, face->foreground);
+             unload_color (f, face->background);
+#if 0
+             unload_pixmap (f, face->stipple);
+#endif
+           }
+         xfree (face);
+       }
+    }
+  xfree (FRAME_FACES (f));
+  FRAME_FACES (f) = 0;
+  FRAME_N_FACES (f) = 0;
+
+  UNBLOCK_INPUT;
+}
+\f
+/* Interning faces in a frame's face array.  */
+
+/* Find a match for NEW_FACE in a FRAME's face array, and add it if we don't
+   find one.  */
+static int
+intern_frame_face (frame, new_face)
+     struct frame *frame;
+     struct face *new_face;
+{
+  int len = FRAME_N_FACES (frame);
+  int i;
+
+  /* Search for a face already on FRAME equivalent to FACE.  */
+  for (i = 0; i < len; i++)
+    {
+      struct face *frame_face = FRAME_FACES (frame)[i];
+      
+      if (frame_face && face_eql (new_face, frame_face))
+       return i;
+    }
+
+  /* We didn't find one; add a new one.  */
+  i = next_face_id++;
+
+  ensure_face_ready (frame, i);
+  bcopy (new_face, FRAME_FACES (frame)[i], sizeof (*new_face));
+  FRAME_FACES (frame)[i]->copy = 1;
+
+  return i;
+}
+
+/* Make face id ID valid on frame F.  */
+
+static void
+ensure_face_ready (f, id)
+     struct frame *f;
+     int id;
+{
+  if (FRAME_N_FACES (f) <= id)
+    {
+      int n = id + 10;
+      int i;
+      if (!FRAME_N_FACES (f))
+       FRAME_FACES (f)
+         = (struct face **) xmalloc (sizeof (struct face *) * n);
+      else
+       FRAME_FACES (f)
+         = (struct face **) xrealloc (FRAME_FACES (f),
+                                      sizeof (struct face *) * n);
+
+      bzero (FRAME_FACES (f) + FRAME_N_FACES (f),
+            (n - FRAME_N_FACES (f)) * sizeof (struct face *));
+      FRAME_N_FACES (f) = n;
+    }
+
+  if (FRAME_FACES (f) [id] == 0)
+    FRAME_FACES (f) [id] = allocate_face ();
+}
+\f
+/* Computing faces appropriate for a given piece of text in a buffer.  */
+
+/* Return non-zero if FONT1 and FONT2 have the same size bounding box.
+   We assume that they're both character-cell fonts.  */
+int
+same_size_fonts (font1, font2)
+     XFontStruct *font1, *font2;
+{
+  XCharStruct *bounds1 = &font1->min_bounds;
+  XCharStruct *bounds2 = &font2->min_bounds;
+
+  return (bounds1->width == bounds2->width);
+/* Checking the following caused bad results in some cases
+   when fonts that should be the same size
+   actually have very slightly different size.
+   It is possible that this reintroduces the bug whereby line positions
+   were not right.  However, the right way to fix that is to change xterm.c
+   so that the vertical positions of lines
+   depend only on the height of the frame's font.
+         && bounds1->ascent == bounds2->ascent
+         && bounds1->descent == bounds2->descent);  */
+}
+
 /* Modify face TO by copying from FROM all properties which have
    nondefault settings.  */
-
 static void 
 merge_faces (from, to)
      struct face *from, *to;
 {
-  if (from->font != (XFontStruct *)FACE_DEFAULT)
-    {
-      to->font = from->font;
-    }
+  /* Only merge the font if it's the same size as the base font.  */
+  if (from->font != (XFontStruct *) FACE_DEFAULT
+      && same_size_fonts (from->font, to->font))
+    to->font = from->font;
   if (from->foreground != FACE_DEFAULT)
     to->foreground = from->foreground;
   if (from->background != FACE_DEFAULT)
@@ -232,6 +634,27 @@ merge_faces (from, to)
     to->underline = from->underline;
 }
 
+/* Set up the basic set of facial parameters, based on the frame's
+   data; all faces are deltas applied to this.  */
+static void
+compute_base_face (f, face)
+     FRAME_PTR f;
+     struct face *face;
+{
+  struct x_display *d = f->display.x;
+  
+  face->gc = 0;
+  face->foreground = d->foreground_pixel;
+  face->background = d->background_pixel;
+  face->font = d->font;
+  face->stipple = 0;
+  face->underline = 0;
+
+  /* Avoid a face comparison by making this invalid.  */
+  face->cached_index = -1;
+}
+
+
 struct sortvec
 {
   Lisp_Object overlay;
@@ -239,47 +662,100 @@ struct sortvec
   int priority;
 };
 
-/* Return the display face associated with a buffer position POS.
+static int
+sort_overlays (s1, s2)
+     struct sortvec *s1, *s2;
+{
+  if (s1->priority != s2->priority)
+    return s1->priority - s2->priority;
+  if (s1->beg != s2->beg)
+    return s1->beg - s2->beg;
+  if (s1->end != s2->end)
+    return s2->end - s1->end;
+  return 0;
+}
+
+/* Return the face ID associated with a buffer position POS.
    Store into *ENDPTR the position at which a different face is needed.
    This does not take account of glyphs that specify their own face codes.
-   F is the frame in use for display, and W is the window.  */
+   F is the frame in use for display, and W is a window displaying
+   the current buffer.
 
-struct face *
-compute_char_face (f, w, pos, endptr)
+   REGION_BEG, REGION_END delimit the region, so it can be highlighted.  */
+
+int
+compute_char_face (f, w, pos, region_beg, region_end, endptr)
      struct frame *f;
      struct window *w;
      int pos;
+     int region_beg, region_end;
      int *endptr;
 {
   struct face face;
-  Lisp_Object prop, position, length;
-  Lisp_Object overlay, start, end;
+  Lisp_Object prop, position;
   int i, j, noverlays;
   int facecode;
-  int endpos;
   Lisp_Object *overlay_vec;
-  int len;
   struct sortvec *sortvec;
   Lisp_Object frame;
+  int endpos;
+
+  /* W must display the current buffer.  We could write this function
+     to use the frame and buffer of W, but right now it doesn't.  */
+  if (XBUFFER (w->buffer) != current_buffer)
+    abort ();
 
   XSET (frame, Lisp_Frame, f);
 
+  endpos = ZV;
+  if (pos < region_beg && region_beg < endpos)
+    endpos = region_beg;
+
   XFASTINT (position) = pos;
-  prop = Fget_text_property (position, Qface);
+  prop = Fget_text_property (position, Qface, w->buffer);
+  {
+    Lisp_Object end;
+
+    end = Fnext_single_property_change (position, Qface, w->buffer);
+    if (INTEGERP (end))
+      endpos = XINT (end);
+  }
+
+  {
+    int next_overlay;
+    int len;
+
+    /* First try with room for 40 overlays.  */
+    len = 40;
+    overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+    
+    noverlays = overlays_at (pos, 0, &overlay_vec, &len, &next_overlay);
+
+    /* If there are more than 40,
+       make enough space for all, and try again.  */
+    if (noverlays > len)
+      {
+       len = noverlays;
+       overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+       noverlays = overlays_at (pos, 0, &overlay_vec, &len, &next_overlay);
+      }
+
+    if (next_overlay < endpos)
+      endpos = next_overlay;
+  }
 
-  len = 10;
-  overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
-  noverlays = overlays_at (pos, &overlay_vec, &len, &endpos);
+  *endptr = endpos;
 
   /* Optimize the default case.  */
-  if (noverlays == 0 && NILP (prop))
-    return FRAME_DEFAULT_FACE (f);
+  if (noverlays == 0 && NILP (prop)
+      && !(pos >= region_beg && pos < region_end))
+    return 0;
 
-  bcopy (FRAME_DEFAULT_FACE (f), &face, sizeof (struct face));
+  compute_base_face (f, &face);
 
   if (!NILP (prop))
     {
-      facecode = face_name_id_number (frame, prop);
+      facecode = face_name_id_number (f, prop);
       if (facecode >= 0 && facecode < FRAME_N_FACES (f)
          && FRAME_FACES (f) [facecode] != 0)
        merge_faces (FRAME_FACES (f) [facecode], &face);
@@ -290,7 +766,7 @@ compute_char_face (f, w, pos, endptr)
 
   for (i = 0, j = 0; i < noverlays; i++)
     {
-      overlay = overlay_vec[i];
+      Lisp_Object overlay = overlay_vec[i];
 
       if (OVERLAY_VALID (overlay)
          && OVERLAY_POSITION (OVERLAY_START (overlay)) > 0
@@ -301,7 +777,8 @@ compute_char_face (f, w, pos, endptr)
 
          /* Also ignore overlays limited to one window
             if it's not the window we are using.  */
-         if (NILP (window) || XWINDOW (window) == w)
+         if (XTYPE (window) != Lisp_Window
+             || XWINDOW (window) == w)
            {
              Lisp_Object tem;
 
@@ -323,306 +800,91 @@ compute_char_face (f, w, pos, endptr)
 
   /* Sort the overlays into the proper order: increasing priority.  */
 
-  qsort (sortvec, noverlays, sizeof (struct sortvec), sort_overlays);
+  if (noverlays > 1)
+    qsort (sortvec, noverlays, sizeof (struct sortvec), sort_overlays);
 
   /* Now merge the overlay data in that order.  */
-
   for (i = 0; i < noverlays; i++)
     {
-      prop = Foverlay_get (overlay_vec[i], Qface);
+      prop = Foverlay_get (sortvec[i].overlay, Qface);
       if (!NILP (prop))
        {
          Lisp_Object oend;
          int oendpos;
 
-         facecode = face_name_id_number (frame, prop);
+         facecode = face_name_id_number (f, prop);
          if (facecode >= 0 && facecode < FRAME_N_FACES (f)
              && FRAME_FACES (f) [facecode] != 0)
            merge_faces (FRAME_FACES (f) [facecode], &face);
 
-         oend = OVERLAY_END (overlay_vec[i]);
+         oend = OVERLAY_END (sortvec[i].overlay);
          oendpos = OVERLAY_POSITION (oend);
-         if (oendpos > endpos)
+         if (oendpos < endpos)
            endpos = oendpos;
        }
     }
 
-  xfree (overlay_vec);
+  if (pos >= region_beg && pos < region_end)
+    {
+      if (region_end < endpos)
+       endpos = region_end;
+      if (region_face >= 0 && region_face < next_face_id)
+       merge_faces (FRAME_FACES (f) [region_face], &face);
+    }
 
   *endptr = endpos;
 
-  return get_display_face (f, &face);
+  return intern_frame_face (f, &face);
 }
 
+/* Return the face ID to use to display a special glyph which selects
+   FACE_CODE as the face ID, assuming that ordinarily the face would
+   be BASIC_FACE.  F is the frame.  */
 int
-sort_overlays (s1, s2)
-     struct sortvec *s1, *s2;
-{
-  if (s1->priority != s2->priority)
-    return s1->priority - s2->priority;
-  if (s1->beg != s2->beg)
-    return s1->beg - s2->beg;
-  if (s1->end != s2->end)
-    return s2->end - s1->end;
-  return 0;
-}
-
-/* Return the display face to use to display a special glyph
-   which selects FACE_CODE as the face ID,
-   assuming that ordinarily the face would be BASIC_FACE.
-   F is the frame.  */
-
-struct face *
-compute_glyph_face (f, basic_face, face_code)
+compute_glyph_face (f, face_code)
      struct frame *f;
-     struct face *basic_face;
      int face_code;
 {
   struct face face;
 
-  bcopy (basic_face, &face, sizeof (struct face));
+  compute_base_face (f, &face);
 
   if (face_code >= 0 && face_code < FRAME_N_FACES (f)
       && FRAME_FACES (f) [face_code] != 0)
     merge_faces (FRAME_FACES (f) [face_code], &face);
 
-  return get_display_face (f, &face);
+  return intern_frame_face (f, &face);
 }
-\f
-/* Given a frame face, return an equivalent display face
-   (one which has a graphics context).  */
 
-static struct face *
-get_display_face (f, face)
-     struct frame *f;
-     struct face *face;
-{
-  struct face *result;
-
-  /* Does the face have a GC already?  */
-  if (face->gc)
-    return face;
-  
-  /* If it's equivalent to the default face, use that.  */
-  if (face->font == FRAME_DEFAULT_FACE (f)->font
-      && face->foreground == FRAME_DEFAULT_FACE (f)->foreground
-      && face->background == FRAME_DEFAULT_FACE (f)->background
-      && face->stipple == FRAME_DEFAULT_FACE (f)->stipple
-      && face->underline == FRAME_DEFAULT_FACE (f)->underline)
-    {
-      if (!FRAME_DEFAULT_FACE (f)->gc)
-       build_face (f, FRAME_DEFAULT_FACE (f));
-      return FRAME_DEFAULT_FACE (f);
-    }
-
-  /* If it's equivalent to the mode line face, use that.  */
-  if (face->font == FRAME_MODE_LINE_FACE (f)->font
-      && face->foreground == FRAME_MODE_LINE_FACE (f)->foreground
-      && face->background == FRAME_MODE_LINE_FACE (f)->background
-      && face->stipple == FRAME_MODE_LINE_FACE (f)->stipple
-      && face->underline == FRAME_MODE_LINE_FACE (f)->underline)
-    {
-      if (!FRAME_MODE_LINE_FACE (f)->gc)
-       build_face (f, FRAME_MODE_LINE_FACE (f));
-      return FRAME_MODE_LINE_FACE (f);
-    }
-
-  /* Get a specialized display face.  */
-  return get_cached_face (f, face);
-}
-
-\f
-/* Allocate a new face */
-static struct face *
-allocate_face ()
-{
-  struct face *result = (struct face *) xmalloc (sizeof (struct face));
-  bzero (result, sizeof (struct face));
-  result->font = (XFontStruct *) FACE_DEFAULT;
-  result->foreground = FACE_DEFAULT;
-  result->background = FACE_DEFAULT;
-  result->stipple = FACE_DEFAULT;
-  return result;
-}
-
-/* Make face id ID valid on frame F.  */
 
+/* Recompute the GC's for the default and modeline faces.
+   We call this after changing frame parameters on which those GC's
+   depend.  */
 void
-ensure_face_ready (f, id)
-     struct frame *f;
-     int id;
+recompute_basic_faces (f)
+     FRAME_PTR f;
 {
-  if (FRAME_N_FACES (f) <= id)
-    {
-      int n = id + 10;
-      int i;
-      if (!FRAME_N_FACES (f))
-       FRAME_FACES (f)
-         = (struct face **) xmalloc (sizeof (struct face *) * n);
-      else
-       FRAME_FACES (f)
-         = (struct face **) xrealloc (FRAME_FACES (f),
-                                      sizeof (struct face *) * n);
-
-      bzero (FRAME_FACES (f) + FRAME_N_FACES (f),
-            (n - FRAME_N_FACES (f)) * sizeof (struct face *));
-      FRAME_N_FACES (f) = n;
-    }
-
-  if (FRAME_FACES (f) [id] == 0)
-    FRAME_FACES (f) [id] = allocate_face ();
-}
-\f
-/* Allocating, freeing, and duplicating fonts, colors, and pixmaps.  */
-
-#ifdef HAVE_X_WINDOWS
-
-static XFontStruct *
-load_font (f, name)
-     struct frame *f;
-     Lisp_Object name;
-{
-  XFontStruct *font;
-
-  if (NILP (name))
-    return (XFontStruct *) FACE_DEFAULT;
-
-  CHECK_STRING (name, 0);
-  BLOCK_INPUT;
-  font = XLoadQueryFont (x_current_display, (char *) XSTRING (name)->data);
-  UNBLOCK_INPUT;
-
-  if (! font)
-    Fsignal (Qerror, Fcons (build_string ("undefined font"),
-                           Fcons (name, Qnil)));
-  return font;
-}
-
-static void
-unload_font (f, font)
-     struct frame *f;
-     XFontStruct *font;
-{
-  if (!font || font == ((XFontStruct *) FACE_DEFAULT))
+  /* If the frame's faces haven't been initialized yet, don't worry about
+     this stuff.  */
+  if (FRAME_N_FACES (f) < 2)
     return;
-  XFreeFont (x_current_display, font);
-}
-
-static unsigned long
-load_color (f, name)
-     struct frame *f;
-     Lisp_Object name;
-{
-  Display *dpy = x_current_display;
-  Colormap cmap;
-  XColor color;
-  int result;
-
-  if (NILP (name))
-    return FACE_DEFAULT;
-
-  cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
-
-  CHECK_STRING (name, 0);
-  BLOCK_INPUT;
-  result = XParseColor (dpy, cmap, (char *) XSTRING (name)->data, &color);
-  UNBLOCK_INPUT;
-  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;
-}
 
-static void
-unload_color (f, pixel)
-     struct frame *f;
-     Pixel pixel;
-{
-  Colormap cmap;
-  Display *dpy = x_current_display;
-  if (pixel == FACE_DEFAULT)
-    return;
-  cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
   BLOCK_INPUT;
-  XFreeColors (dpy, cmap, &pixel, 1, 0);
-  UNBLOCK_INPUT;
-}
 
-#endif /* HAVE_X_WINDOWS */
-
-\f
-/* frames */
-
-void
-init_frame_faces (f)
-     struct frame *f;
-{
-  struct frame *other_frame = 0;
-  Lisp_Object rest;
+  if (FRAME_DEFAULT_FACE (f)->gc)
+    XFreeGC (x_current_display, FRAME_DEFAULT_FACE (f)->gc);
+  build_face (f, FRAME_DEFAULT_FACE (f));
 
-  for (rest = Vframe_list; !NILP (rest); rest = Fcdr (rest))
-    {
-      struct frame *f2 = XFRAME (Fcar (rest));
-      if (f2 != f && FRAME_X_P (f2))
-       {
-         other_frame = f2;
-         break;
-       }
-    }
+  if (FRAME_MODE_LINE_FACE (f)->gc)
+    XFreeGC (x_current_display, FRAME_MODE_LINE_FACE (f)->gc);
+  build_face (f, FRAME_MODE_LINE_FACE (f));
 
-  if (other_frame)
-    {
-      /* Make sure this frame's face vector is as big as the others.  */
-      FRAME_N_FACES (f) = FRAME_N_FACES (other_frame);
-      FRAME_FACES (f)
-       = (struct face **) xmalloc (FRAME_N_FACES (f) * sizeof (struct face *));
-
-      /* Make sure the frame has the two basic faces.  */
-      FRAME_DEFAULT_FACE (f)
-       = copy_face (FRAME_DEFAULT_FACE (other_frame));
-      FRAME_MODE_LINE_FACE (f)
-       = copy_face (FRAME_MODE_LINE_FACE (other_frame));
-    }
+  UNBLOCK_INPUT;
 }
 
 
-/* Called from Fdelete_frame?  */
-
-void
-free_screen_faces (f)
-     struct frame *f;
-{
-  Display *dpy = x_current_display;
-  int i;
-
-  for (i = 0; i < FRAME_N_FACES (f); i++)
-    {
-      struct face *face = FRAME_FACES (f) [i];
-      if (! face)
-        continue;
-      if (face->gc)
-       XFreeGC (dpy, face->gc);
-      unload_font (f, face->font);
-      unload_color (f, face->foreground);
-      unload_color (f, face->background);
-#if 0
-      unload_pixmap (f, face->stipple);
-#endif
-      xfree (face);
-    }
-  xfree (FRAME_FACES (f));
-  FRAME_FACES (f) = 0;
-  FRAME_N_FACES (f) = 0;
-}
-
 \f
-/* Lisp interface */
+/* Lisp interface. */
 
 DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0,
        "")
@@ -659,7 +921,8 @@ DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
   for (rest = Vframe_list; !NILP (rest); rest = XCONS (rest)->cdr)
     {
       struct frame *f = XFRAME (XCONS (rest)->car);
-      ensure_face_ready (f, id);
+      if (FRAME_X_P (f))
+       ensure_face_ready (f, id);
     }
   return Qnil;
 }
@@ -684,13 +947,17 @@ 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))
+    return;
+
   ensure_face_ready (f, id);
   face = FRAME_FACES (f) [XFASTINT (face_id)];
 
   if (EQ (attr_name, intern ("font")))
     {
       XFontStruct *font = load_font (f, attr_value);
-      unload_font (f, face->font);
+      if (face->font != f->display.x->font)
+       unload_font (f, face->font);
       face->font = font;
     }
   else if (EQ (attr_name, intern ("foreground")))
@@ -745,6 +1012,17 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
       UNBLOCK_INPUT;
     }
 
+  /* If we're modifying either of the frame's display faces, that
+     means that we're changing the parameters of a fixed face code;
+     since the color/font/whatever is changed but the face ID hasn't,
+     redisplay won't know to redraw the affected sections.  Give it a
+     kick.  */
+  if (id == 0 || id == 1)
+    SET_FRAME_GARBAGED (f);
+  else
+    /* Otherwise, it's enough to tell it to redisplay the text.  */
+    windows_or_buffers_changed = 1;
+
   return Qnil;
 }
 
@@ -760,20 +1038,24 @@ DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
    but it's as easy to use the "right" frame to look it up
    as to use any other one.)  */
 
-static Lisp_Object
-face_name_id_number (frame, name)
-     Lisp_Object frame, name;
+int
+face_name_id_number (f, name)
+     FRAME_PTR f;
+     Lisp_Object name;
 {
   Lisp_Object tem;
 
-  CHECK_FRAME (frame, 0);
-  tem = Fcdr (Fassq (name, XFRAME (frame)->face_alist));
+  tem = Fcdr (Fassq (name, f->face_alist));
+  if (NILP (tem))
+    return 0;
   CHECK_VECTOR (tem, 0);
   tem = XVECTOR (tem)->contents[2];
   CHECK_NUMBER (tem, 0);
   return XINT (tem);
 }
 \f
+/* Emacs initialization.  */
+
 void
 syms_of_xfaces ()
 {
@@ -784,9 +1066,17 @@ syms_of_xfaces ()
   Qpriority = intern ("priority");
   staticpro (&Qpriority);
 
+  DEFVAR_INT ("region-face", &region_face,
+    "Face number to use to highlight the region\n\
+The region is highlighted with this face\n\
+when Transient Mark mode is enabled and the mark is active.");
+
   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_X_WINDOWS */
+