]> code.delx.au - gnu-emacs/blobdiff - src/xfaces.c
Merged from miles@gnu.org--gnu-2005 (patch 281-285)
[gnu-emacs] / src / xfaces.c
index f664249a290f9f35cc72d35b7186ce31b577a63d..2884bccb3b98e410d32999c130bdfed4d440f5ec 100644 (file)
@@ -1,5 +1,5 @@
 /* xfaces.c -- "Face" primitives.
 /* xfaces.c -- "Face" primitives.
-   Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation.
 
 This file is part of GNU Emacs.
    Free Software Foundation.
 
 This file is part of GNU Emacs.
@@ -336,6 +336,8 @@ extern Lisp_Object Qmode_line;
 
 Lisp_Object Qface_alias;
 
 
 Lisp_Object Qface_alias;
 
+extern Lisp_Object Qcircular_list;
+
 /* Default stipple pattern used on monochrome displays.  This stipple
    pattern is used on monochrome displays instead of shades of gray
    for a face background color.  See `set-face-stipple' for possible
 /* Default stipple pattern used on monochrome displays.  This stipple
    pattern is used on monochrome displays instead of shades of gray
    for a face background color.  See `set-face-stipple' for possible
@@ -388,6 +390,10 @@ Lisp_Object Qforeground_color, Qbackground_color;
 Lisp_Object Qface;
 extern Lisp_Object Qmouse_face;
 
 Lisp_Object Qface;
 extern Lisp_Object Qmouse_face;
 
+/* Property for basic faces which other faces cannot inherit.  */
+
+Lisp_Object Qface_no_inherit;
+
 /* Error symbol for wrong_type_argument in load_pixmap.  */
 
 Lisp_Object Qbitmap_spec_p;
 /* Error symbol for wrong_type_argument in load_pixmap.  */
 
 Lisp_Object Qbitmap_spec_p;
@@ -467,7 +473,7 @@ struct named_merge_point;
 
 static void map_tty_color P_ ((struct frame *, struct face *,
                               enum lface_attribute_index, int *));
 
 static void map_tty_color P_ ((struct frame *, struct face *,
                               enum lface_attribute_index, int *));
-static Lisp_Object resolve_face_name P_ ((Lisp_Object));
+static Lisp_Object resolve_face_name P_ ((Lisp_Object, int));
 static int may_use_scalable_font_p P_ ((const char *));
 static void set_font_frame_param P_ ((Lisp_Object, Lisp_Object));
 static int better_font_p P_ ((int *, struct font_name *, struct font_name *,
 static int may_use_scalable_font_p P_ ((const char *));
 static void set_font_frame_param P_ ((Lisp_Object, Lisp_Object));
 static int better_font_p P_ ((int *, struct font_name *, struct font_name *,
@@ -737,7 +743,7 @@ x_free_gc (f, gc)
      GC gc;
 {
   BLOCK_INPUT;
      GC gc;
 {
   BLOCK_INPUT;
-  xassert (--ngcs >= 0);
+  IF_DEBUG (xassert (--ngcs >= 0));
   XFreeGC (FRAME_X_DISPLAY (f), gc);
   UNBLOCK_INPUT;
 }
   XFreeGC (FRAME_X_DISPLAY (f), gc);
   UNBLOCK_INPUT;
 }
@@ -770,7 +776,7 @@ x_free_gc (f, gc)
      GC gc;
 {
   BLOCK_INPUT;
      GC gc;
 {
   BLOCK_INPUT;
-  xassert (--ngcs >= 0);
+  IF_DEBUG (xassert (--ngcs >= 0));
   xfree (gc);
   UNBLOCK_INPUT;
 }
   xfree (gc);
   UNBLOCK_INPUT;
 }
@@ -1070,6 +1076,9 @@ clear_font_table (dpyinfo)
 #endif
 #ifdef WINDOWSNT
       w32_unload_font (dpyinfo, font_info->font);
 #endif
 #ifdef WINDOWSNT
       w32_unload_font (dpyinfo, font_info->font);
+#endif
+#ifdef MAC_OS
+      mac_unload_font (dpyinfo, font_info->font);
 #endif
       UNBLOCK_INPUT;
 
 #endif
       UNBLOCK_INPUT;
 
@@ -1509,7 +1518,7 @@ face_color_supported_p (f, color_name, background_p)
 
   XSETFRAME (frame, f);
   return
 
   XSETFRAME (frame, f);
   return
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
     FRAME_WINDOW_P (f)
     ? (!NILP (Fxw_display_color_p (frame))
        || xstricmp (color_name, "black") == 0
     FRAME_WINDOW_P (f)
     ? (!NILP (Fxw_display_color_p (frame))
        || xstricmp (color_name, "black") == 0
@@ -3008,7 +3017,7 @@ the WIDTH times as wide as FACE on FRAME.  */)
     {
       /* This is of limited utility since it works with character
         widths.  Keep it for compatibility.  --gerd.  */
     {
       /* This is of limited utility since it works with character
         widths.  Keep it for compatibility.  --gerd.  */
-      int face_id = lookup_named_face (f, face, 0);
+      int face_id = lookup_named_face (f, face, 0, 0);
       struct face *face = (face_id < 0
                           ? NULL
                           : FACE_FROM_ID (f, face_id));
       struct face *face = (face_id < 0
                           ? NULL
                           : FACE_FROM_ID (f, face_id));
@@ -3197,27 +3206,63 @@ push_named_merge_point (struct named_merge_point *new_named_merge_point,
 
 \f
 
 
 \f
 
+static Lisp_Object
+internal_resolve_face_name (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Fget (args[0], args[1]);
+}
+
+static Lisp_Object
+resolve_face_name_error (ignore)
+     Lisp_Object ignore;
+{
+  return Qnil;
+}
 
 /* Resolve face name FACE_NAME.  If FACE_NAME is a string, intern it
 
 /* Resolve face name FACE_NAME.  If FACE_NAME is a string, intern it
-   to make it a symvol.  If FACE_NAME is an alias for another face,
-   return that face's name.  */
+   to make it a symbol.  If FACE_NAME is an alias for another face,
+   return that face's name.
+
+   Return default face in case of errors.  */
 
 static Lisp_Object
 
 static Lisp_Object
-resolve_face_name (face_name)
+resolve_face_name (face_name, signal_p)
      Lisp_Object face_name;
      Lisp_Object face_name;
+     int signal_p;
 {
 {
-  Lisp_Object aliased;
+  Lisp_Object orig_face;
+  Lisp_Object tortoise, hare;
 
   if (STRINGP (face_name))
     face_name = intern (SDATA (face_name));
 
 
   if (STRINGP (face_name))
     face_name = intern (SDATA (face_name));
 
-  while (SYMBOLP (face_name))
+  if (NILP (face_name) || !SYMBOLP (face_name))
+    return face_name;
+
+  orig_face = face_name;
+  tortoise = hare = face_name;
+
+  while (1)
     {
     {
-      aliased = Fget (face_name, Qface_alias);
-      if (NILP (aliased))
+      face_name = hare;
+      hare = Fget (hare, Qface_alias);
+      if (NILP (hare) || !SYMBOLP (hare))
        break;
        break;
-      else
-       face_name = aliased;
+
+      face_name = hare;
+      hare = Fget (hare, Qface_alias);
+      if (NILP (hare) || !SYMBOLP (hare))
+       break;
+
+      tortoise = Fget (tortoise, Qface_alias);
+      if (EQ (hare, tortoise))
+       {
+         if (signal_p)
+           Fsignal (Qcircular_list, Fcons (orig_face, Qnil));
+         return Qdefault;
+       }
     }
 
   return face_name;
     }
 
   return face_name;
@@ -3241,7 +3286,7 @@ lface_from_face_name (f, face_name, signal_p)
 {
   Lisp_Object lface;
 
 {
   Lisp_Object lface;
 
-  face_name = resolve_face_name (face_name);
+  face_name = resolve_face_name (face_name, signal_p);
 
   if (f)
     lface = assq_no_quit (face_name, f->face_alist);
 
   if (f)
     lface = assq_no_quit (face_name, f->face_alist);
@@ -3431,8 +3476,8 @@ set_lface_from_font_name (f, lface, fontname, force_p, may_fail_p)
    call into lisp.  */
 
 Lisp_Object
    call into lisp.  */
 
 Lisp_Object
-merge_face_heights (from, to, invalid, gcpro)
-     Lisp_Object from, to, invalid, gcpro;
+merge_face_heights (from, to, invalid)
+     Lisp_Object from, to, invalid;
 {
   Lisp_Object result = invalid;
 
 {
   Lisp_Object result = invalid;
 
@@ -3457,16 +3502,11 @@ merge_face_heights (from, to, invalid, gcpro)
       /* Call function with current height as argument.
         From is the new height.  */
       Lisp_Object args[2];
       /* Call function with current height as argument.
         From is the new height.  */
       Lisp_Object args[2];
-      struct gcpro gcpro1;
-
-      GCPRO1 (gcpro);
 
       args[0] = from;
       args[1] = to;
       result = safe_call (2, args);
 
 
       args[0] = from;
       args[1] = to;
       result = safe_call (2, args);
 
-      UNGCPRO;
-
       /* Ensure that if TO was absolute, so is the result.  */
       if (INTEGERP (to) && !INTEGERP (result))
        result = invalid;
       /* Ensure that if TO was absolute, so is the result.  */
       if (INTEGERP (to) && !INTEGERP (result))
        result = invalid;
@@ -3519,8 +3559,7 @@ merge_face_vectors (f, from, to, named_merge_points)
     if (!UNSPECIFIEDP (from[i]))
       {
        if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
     if (!UNSPECIFIEDP (from[i]))
       {
        if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
-         to[i] = merge_face_heights (from[i], to[i], to[i],
-                                     named_merge_points);
+         to[i] = merge_face_heights (from[i], to[i], to[i]);
        else
          to[i] = from[i];
       }
        else
          to[i] = from[i];
       }
@@ -3547,11 +3586,16 @@ merge_named_face (f, face_name, to, named_merge_points)
   if (push_named_merge_point (&named_merge_point,
                              face_name, &named_merge_points))
     {
   if (push_named_merge_point (&named_merge_point,
                              face_name, &named_merge_points))
     {
+      struct gcpro gcpro1;
       Lisp_Object from[LFACE_VECTOR_SIZE];
       int ok = get_lface_attributes (f, face_name, from, 0);
 
       if (ok)
       Lisp_Object from[LFACE_VECTOR_SIZE];
       int ok = get_lface_attributes (f, face_name, from, 0);
 
       if (ok)
-       merge_face_vectors (f, from, to, named_merge_points);
+       {
+         GCPRO1 (named_merge_point.face_name);
+         merge_face_vectors (f, from, to, named_merge_points);
+         UNGCPRO;
+       }
 
       return ok;
     }
 
       return ok;
     }
@@ -3629,7 +3673,10 @@ merge_face_ref (f, face_ref, to, err_msgs, named_merge_points)
              Lisp_Object value = XCAR (XCDR (face_ref));
              int err = 0;
 
              Lisp_Object value = XCAR (XCDR (face_ref));
              int err = 0;
 
-             if (EQ (keyword, QCfamily))
+             /* Specifying `unspecified' is a no-op.  */
+             if (EQ (value, Qunspecified))
+               ;
+             else if (EQ (keyword, QCfamily))
                {
                  if (STRINGP (value))
                    to[LFACE_FAMILY_INDEX] = value;
                {
                  if (STRINGP (value))
                    to[LFACE_FAMILY_INDEX] = value;
@@ -3639,8 +3686,7 @@ merge_face_ref (f, face_ref, to, err_msgs, named_merge_points)
              else if (EQ (keyword, QCheight))
                {
                  Lisp_Object new_height =
              else if (EQ (keyword, QCheight))
                {
                  Lisp_Object new_height =
-                   merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
-                                       Qnil, Qnil);
+                   merge_face_heights (value, to[LFACE_HEIGHT_INDEX], Qnil);
 
                  if (! NILP (new_height))
                    to[LFACE_HEIGHT_INDEX] = new_height;
 
                  if (! NILP (new_height))
                    to[LFACE_HEIGHT_INDEX] = new_height;
@@ -3865,8 +3911,11 @@ Value is a vector of face attributes.  */)
      depend on the face, make sure they are all removed.  This is done
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
      depend on the face, make sure they are all removed.  This is done
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
-  ++face_change_count;
-  ++windows_or_buffers_changed;
+  if (NILP (Fget (face, Qface_no_inherit)))
+    {
+      ++face_change_count;
+      ++windows_or_buffers_changed;
+    }
 
   xassert (LFACEP (lface));
   check_lface (lface);
 
   xassert (LFACEP (lface));
   check_lface (lface);
@@ -3941,8 +3990,11 @@ The value is TO.  */)
      depend on the face, make sure they are all removed.  This is done
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
      depend on the face, make sure they are all removed.  This is done
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
-  ++face_change_count;
-  ++windows_or_buffers_changed;
+  if (NILP (Fget (to, Qface_no_inherit)))
+    {
+      ++face_change_count;
+      ++windows_or_buffers_changed;
+    }
 
   return to;
 }
 
   return to;
 }
@@ -3969,7 +4021,7 @@ FRAME 0 means change the face on all frames, and change the default
   CHECK_SYMBOL (face);
   CHECK_SYMBOL (attr);
 
   CHECK_SYMBOL (face);
   CHECK_SYMBOL (attr);
 
-  face = resolve_face_name (face);
+  face = resolve_face_name (face, 1);
 
   /* If FRAME is 0, change face on all frames, and change the
      default for new frames.  */
 
   /* If FRAME is 0, change face on all frames, and change the
      default for new frames.  */
@@ -4021,7 +4073,7 @@ FRAME 0 means change the face on all frames, and change the default
                  /* The default face must have an absolute size,
                     otherwise, we do a test merge with a random
                     height to see if VALUE's ok. */
                  /* The default face must have an absolute size,
                     otherwise, we do a test merge with a random
                     height to see if VALUE's ok. */
-                 : merge_face_heights (value, make_number (10), Qnil, Qnil));
+                 : merge_face_heights (value, make_number (10), Qnil));
 
          if (!INTEGERP (test) || XINT (test) <= 0)
            signal_error ("Invalid face height", value);
 
          if (!INTEGERP (test) || XINT (test) <= 0)
            signal_error ("Invalid face height", value);
@@ -4137,7 +4189,7 @@ FRAME 0 means change the face on all frames, and change the default
                }
              else if (EQ (k, QCcolor))
                {
                }
              else if (EQ (k, QCcolor))
                {
-                 if (!STRINGP (v) || SCHARS (v) == 0)
+                 if (!NILP (v) && (!STRINGP (v) || SCHARS (v) == 0))
                    break;
                }
              else if (EQ (k, QCstyle))
                    break;
                }
              else if (EQ (k, QCstyle))
@@ -4299,6 +4351,7 @@ FRAME 0 means change the face on all frames, and change the default
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
   if (!EQ (frame, Qt)
      by incrementing face_change_count.  The next call to
      init_iterator will then free realized faces.  */
   if (!EQ (frame, Qt)
+      && NILP (Fget (face, Qface_no_inherit))
       && (EQ (attr, QCfont)
          || NILP (Fequal (old_value, value))))
     {
       && (EQ (attr, QCfont)
          || NILP (Fequal (old_value, value))))
     {
@@ -4451,6 +4504,7 @@ update_face_from_frame_parameter (f, param, new_value)
      struct frame *f;
      Lisp_Object param, new_value;
 {
      struct frame *f;
      Lisp_Object param, new_value;
 {
+  Lisp_Object face = Qnil;
   Lisp_Object lface;
 
   /* If there are no faces yet, give up.  This is the case when called
   Lisp_Object lface;
 
   /* If there are no faces yet, give up.  This is the case when called
@@ -4459,17 +4513,10 @@ update_face_from_frame_parameter (f, param, new_value)
   if (NILP (f->face_alist))
     return;
 
   if (NILP (f->face_alist))
     return;
 
-  /* Changing a named face means that all realized faces depending on
-     that face are invalid.  Since we cannot tell which realized faces
-     depend on the face, make sure they are all removed.  This is done
-     by incrementing face_change_count.  The next call to
-     init_iterator will then free realized faces.  */
-  ++face_change_count;
-  ++windows_or_buffers_changed;
-
   if (EQ (param, Qforeground_color))
     {
   if (EQ (param, Qforeground_color))
     {
-      lface = lface_from_face_name (f, Qdefault, 1);
+      face = Qdefault;
+      lface = lface_from_face_name (f, face, 1);
       LFACE_FOREGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
       realize_basic_faces (f);
       LFACE_FOREGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
       realize_basic_faces (f);
@@ -4484,29 +4531,45 @@ update_face_from_frame_parameter (f, param, new_value)
       XSETFRAME (frame, f);
       call1 (Qframe_update_face_colors, frame);
 
       XSETFRAME (frame, f);
       call1 (Qframe_update_face_colors, frame);
 
-      lface = lface_from_face_name (f, Qdefault, 1);
+      face = Qdefault;
+      lface = lface_from_face_name (f, face, 1);
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
       realize_basic_faces (f);
     }
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
       realize_basic_faces (f);
     }
-  if (EQ (param, Qborder_color))
+  else if (EQ (param, Qborder_color))
     {
     {
-      lface = lface_from_face_name (f, Qborder, 1);
+      face = Qborder;
+      lface = lface_from_face_name (f, face, 1);
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
   else if (EQ (param, Qcursor_color))
     {
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
   else if (EQ (param, Qcursor_color))
     {
-      lface = lface_from_face_name (f, Qcursor, 1);
+      face = Qcursor;
+      lface = lface_from_face_name (f, face, 1);
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
   else if (EQ (param, Qmouse_color))
     {
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
   else if (EQ (param, Qmouse_color))
     {
-      lface = lface_from_face_name (f, Qmouse, 1);
+      face = Qmouse;
+      lface = lface_from_face_name (f, face, 1);
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
       LFACE_BACKGROUND (lface) = (STRINGP (new_value)
                                  ? new_value : Qunspecified);
     }
+
+  /* Changing a named face means that all realized faces depending on
+     that face are invalid.  Since we cannot tell which realized faces
+     depend on the face, make sure they are all removed.  This is done
+     by incrementing face_change_count.  The next call to
+     init_iterator will then free realized faces.  */
+  if (!NILP (face)
+      && NILP (Fget (face, Qface_no_inherit)))
+    {
+      ++face_change_count;
+      ++windows_or_buffers_changed;
+    }
 }
 
 
 }
 
 
@@ -4670,16 +4733,27 @@ x_update_menu_appearance (f)
        {
 #ifdef USE_MOTIF
          const char *suffix = "List";
        {
 #ifdef USE_MOTIF
          const char *suffix = "List";
+         Bool motif = True;
 #else
          const char *suffix = "";
 #else
          const char *suffix = "";
+         Bool motif = False;
+#endif
+#if defined HAVE_X_I18N
+         extern char *xic_create_fontsetname
+           P_ ((char *base_fontname, Bool motif));
+         char *fontsetname = xic_create_fontsetname (face->font_name, motif);
+#else
+         char *fontsetname = face->font_name;
 #endif
          sprintf (line, "%s.pane.menubar*font%s: %s",
 #endif
          sprintf (line, "%s.pane.menubar*font%s: %s",
-                  myname, suffix, face->font_name);
+                  myname, suffix, fontsetname);
          XrmPutLineResource (&rdb, line);
          sprintf (line, "%s.%s*font%s: %s",
          XrmPutLineResource (&rdb, line);
          sprintf (line, "%s.%s*font%s: %s",
-                  myname, popup_path, suffix, face->font_name);
+                  myname, popup_path, suffix, fontsetname);
          XrmPutLineResource (&rdb, line);
          changed_p = 1;
          XrmPutLineResource (&rdb, line);
          changed_p = 1;
+         if (fontsetname != face->font_name)
+           xfree (fontsetname);
        }
 
       if (changed_p && f->output_data.x->menubar_widget)
        }
 
       if (changed_p && f->output_data.x->menubar_widget)
@@ -4716,7 +4790,7 @@ the result will be absolute, otherwise it will be relative.  */)
   if (EQ (value1, Qunspecified))
     return value2;
   else if (EQ (attribute, QCheight))
   if (EQ (value1, Qunspecified))
     return value2;
   else if (EQ (attribute, QCheight))
-    return merge_face_heights (value1, value2, value1, Qnil);
+    return merge_face_heights (value1, value2, value1);
   else
     return value1;
 }
   else
     return value1;
 }
@@ -4904,7 +4978,7 @@ If FRAME is omitted or nil, use the selected frame.  */)
   else
     {
       struct frame *f = frame_or_selected_frame (frame, 1);
   else
     {
       struct frame *f = frame_or_selected_frame (frame, 1);
-      int face_id = lookup_named_face (f, face, 0);
+      int face_id = lookup_named_face (f, face, 0, 1);
       struct face *face = FACE_FROM_ID (f, face_id);
       return face ? build_string (face->font_name) : Qnil;
     }
       struct face *face = FACE_FROM_ID (f, face_id);
       return face ? build_string (face->font_name) : Qnil;
     }
@@ -5596,10 +5670,11 @@ lookup_face (f, attr, c, base_face)
    isn't realized and cannot be realized.  */
 
 int
    isn't realized and cannot be realized.  */
 
 int
-lookup_named_face (f, symbol, c)
+lookup_named_face (f, symbol, c, signal_p)
      struct frame *f;
      Lisp_Object symbol;
      int c;
      struct frame *f;
      Lisp_Object symbol;
      int c;
+     int signal_p;
 {
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
   Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
 {
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
   Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
@@ -5612,7 +5687,9 @@ lookup_named_face (f, symbol, c)
       default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
     }
 
       default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
     }
 
-  get_lface_attributes (f, symbol, symbol_attrs, 1);
+  if (!get_lface_attributes (f, symbol, symbol_attrs, signal_p))
+    return -1;
+
   bcopy (default_face->lface, attrs, sizeof attrs);
   merge_face_vectors (f, symbol_attrs, attrs, 0);
 
   bcopy (default_face->lface, attrs, sizeof attrs);
   merge_face_vectors (f, symbol_attrs, attrs, 0);
 
@@ -5633,7 +5710,7 @@ ascii_face_of_lisp_face (f, lface_id)
   if (lface_id >= 0 && lface_id < lface_id_to_name_size)
     {
       Lisp_Object face_name = lface_id_to_name[lface_id];
   if (lface_id >= 0 && lface_id < lface_id_to_name_size)
     {
       Lisp_Object face_name = lface_id_to_name[lface_id];
-      face_id = lookup_named_face (f, face_name, 0);
+      face_id = lookup_named_face (f, face_name, 0, 1);
     }
   else
     face_id = -1;
     }
   else
     face_id = -1;
@@ -5739,7 +5816,7 @@ face_with_height (f, face_id, height)
    is assumed to be already realized.  */
 
 int
    is assumed to be already realized.  */
 
 int
-lookup_derived_face (f, symbol, c, face_id)
+lookup_derived_face (f, symbol, c, face_id, signal_p)
      struct frame *f;
      Lisp_Object symbol;
      int c;
      struct frame *f;
      Lisp_Object symbol;
      int c;
@@ -5752,7 +5829,7 @@ lookup_derived_face (f, symbol, c, face_id)
   if (!default_face)
     abort ();
 
   if (!default_face)
     abort ();
 
-  get_lface_attributes (f, symbol, symbol_attrs, 1);
+  get_lface_attributes (f, symbol, symbol_attrs, signal_p);
   bcopy (default_face->lface, attrs, sizeof attrs);
   merge_face_vectors (f, symbol_attrs, attrs, 0);
   return lookup_face (f, attrs, c, default_face);
   bcopy (default_face->lface, attrs, sizeof attrs);
   merge_face_vectors (f, symbol_attrs, attrs, 0);
   return lookup_face (f, attrs, c, default_face);
@@ -7054,8 +7131,9 @@ realize_x_face (cache, attrs, c, base_face)
      int c;
      struct face *base_face;
 {
      int c;
      struct face *base_face;
 {
+  struct face *face = NULL;
 #ifdef HAVE_WINDOW_SYSTEM
 #ifdef HAVE_WINDOW_SYSTEM
-  struct face *face, *default_face;
+  struct face *default_face;
   struct frame *f;
   Lisp_Object stipple, overline, strike_through, box;
 
   struct frame *f;
   Lisp_Object stipple, overline, strike_through, box;
 
@@ -7251,8 +7329,8 @@ realize_x_face (cache, attrs, c, base_face)
     face->stipple = load_pixmap (f, stipple, &face->pixmap_w, &face->pixmap_h);
 
   xassert (FACE_SUITABLE_FOR_CHAR_P (face, c));
     face->stipple = load_pixmap (f, stipple, &face->pixmap_w, &face->pixmap_h);
 
   xassert (FACE_SUITABLE_FOR_CHAR_P (face, c));
-  return face;
 #endif /* HAVE_WINDOW_SYSTEM */
 #endif /* HAVE_WINDOW_SYSTEM */
+  return face;
 }
 
 
 }
 
 
@@ -7668,6 +7746,69 @@ face_at_string_position (w, string, pos, bufpos, region_beg,
 }
 
 
 }
 
 
+/* Merge a face into a realized face.
+
+   F is frame where faces are (to be) realized.
+
+   FACE_NAME is named face to merge.
+
+   If FACE_NAME is nil, FACE_ID is face_id of realized face to merge.
+
+   If FACE_NAME is t, FACE_ID is lface_id of face to merge.
+
+   BASE_FACE_ID is realized face to merge into.
+
+   Return new face id.
+*/
+
+int
+merge_faces (f, face_name, face_id, base_face_id)
+     struct frame *f;
+     Lisp_Object face_name;
+     int face_id, base_face_id;
+{
+  Lisp_Object attrs[LFACE_VECTOR_SIZE];
+  struct face *base_face;
+
+  base_face = FACE_FROM_ID (f, base_face_id);
+  if (!base_face)
+    return base_face_id;
+
+  if (EQ (face_name, Qt))
+    {
+      if (face_id < 0 || face_id >= lface_id_to_name_size)
+       return base_face_id;
+      face_name = lface_id_to_name[face_id];
+      face_id = lookup_derived_face (f, face_name, 0, base_face_id, 1);
+      if (face_id >= 0)
+       return face_id;
+      return base_face_id;
+    }
+
+  /* Begin with attributes from the base face.  */
+  bcopy (base_face->lface, attrs, sizeof attrs);
+
+  if (!NILP (face_name))
+    {
+      if (!merge_named_face (f, face_name, attrs, 0))
+       return base_face_id;
+    }
+  else
+    {
+      struct face *face;
+      if (face_id < 0)
+       return base_face_id;
+      face = FACE_FROM_ID (f, face_id);
+      if (!face)
+       return base_face_id;
+      merge_face_vectors (f, face->lface, attrs, 0);
+    }
+
+  /* Look up a realized face with the given face attributes,
+     or realize a new one for ASCII characters.  */
+  return lookup_face (f, attrs, 0, NULL);
+}
+
 \f
 /***********************************************************************
                                Tests
 \f
 /***********************************************************************
                                Tests
@@ -7683,7 +7824,7 @@ dump_realized_face (face)
 {
   fprintf (stderr, "ID: %d\n", face->id);
 #ifdef HAVE_X_WINDOWS
 {
   fprintf (stderr, "ID: %d\n", face->id);
 #ifdef HAVE_X_WINDOWS
-  fprintf (stderr, "gc: %d\n", (int) face->gc);
+  fprintf (stderr, "gc: %ld\n", (long) face->gc);
 #endif
   fprintf (stderr, "foreground: 0x%lx (%s)\n",
           face->foreground,
 #endif
   fprintf (stderr, "foreground: 0x%lx (%s)\n",
           face->foreground,
@@ -7764,6 +7905,8 @@ syms_of_xfaces ()
 {
   Qface = intern ("face");
   staticpro (&Qface);
 {
   Qface = intern ("face");
   staticpro (&Qface);
+  Qface_no_inherit = intern ("face-no-inherit");
+  staticpro (&Qface_no_inherit);
   Qbitmap_spec_p = intern ("bitmap-spec-p");
   staticpro (&Qbitmap_spec_p);
   Qframe_update_face_colors = intern ("frame-update-face-colors");
   Qbitmap_spec_p = intern ("bitmap-spec-p");
   staticpro (&Qbitmap_spec_p);
   Qframe_update_face_colors = intern ("frame-update-face-colors");