(message_dolog): Give correct args to
[bpt/emacs.git] / src / xfaces.c
index 2d86cd6..d393a60 100644 (file)
@@ -26,17 +26,24 @@ Boston, MA 02111-1307, 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"
@@ -76,7 +83,7 @@ Boston, MA 02111-1307, 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.
@@ -148,9 +155,6 @@ Boston, MA 02111-1307, USA.  */
 \f
 /* Definitions and declarations.  */
 
-/* The number of face-id's in use (same for all frames).  */
-static int next_face_id;
-
 /* The number of the face to use to indicate the region.  */
 static int region_face;
 
@@ -168,6 +172,9 @@ static int new_computed_face ( /* FRAME_PTR, struct face * */ );
 static int intern_computed_face ( /* FRAME_PTR, struct face * */ );
 static void ensure_face_ready ( /* FRAME_PTR, int id */ );
 void recompute_basic_faces ( /* FRAME_PTR f */ );
+static void merge_face_list ( /* FRAME_PTR, struct face *, Lisp_Object */ );
+
+extern Lisp_Object Qforeground_color, Qbackground_color;
 \f
 /* Allocating, copying, and comparing struct faces.  */
 
@@ -178,6 +185,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;
@@ -192,6 +200,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;
@@ -207,6 +216,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
@@ -261,6 +271,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;
 
@@ -290,7 +304,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;
            }
        }
@@ -372,7 +389,7 @@ load_color (f, name)
   CHECK_STRING (name, 0);
   /* 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);
+  result = defined_color (f, (char *) XSTRING (name)->data, &color, 1);
   if (! result)
     Fsignal (Qerror, Fcons (build_string ("undefined color"),
                            Fcons (name, Qnil)));
@@ -560,7 +577,6 @@ 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;
@@ -589,7 +605,6 @@ init_frame_faces (f)
            ensure_face_ready (f, i);
       }
   }
-#endif /* MULTI_FRAME */
 }
 
 
@@ -609,7 +624,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);
@@ -629,7 +645,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);
        }
     }
@@ -754,13 +773,19 @@ frame_update_line_height (f)
      FRAME_PTR f;
 {
   int i;
-  int biggest = FONT_HEIGHT (f->output_data.x->font);
+  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->output_data.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;
       }
@@ -785,6 +810,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)
@@ -811,6 +838,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;
 }
@@ -955,101 +983,92 @@ compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
 
   compute_base_face (f, &face);
 
-  if (CONSP (prop))
+  merge_face_list (f, &face, prop);
+
+  noverlays = sort_overlays (overlay_vec, noverlays, w);
+
+  /* Now merge the overlay data in that order.  */
+  for (i = 0; i < noverlays; i++)
+    {
+      Lisp_Object oend;
+      int oendpos;
+
+      prop = Foverlay_get (overlay_vec[i], propname);
+      merge_face_list (f, &face, prop);
+
+      oend = OVERLAY_END (overlay_vec[i]);
+      oendpos = OVERLAY_POSITION (oend);
+      if (oendpos < endpos)
+       endpos = oendpos;
+    }
+
+  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_PARAM_FACES (f)[region_face], &face);
+    }
+
+  *endptr = endpos;
+
+  return intern_computed_face (f, &face);
+}
+
+static void
+merge_face_list (f, face, prop)
+     FRAME_PTR f;
+     struct face *face;
+     Lisp_Object prop;
+{
+  Lisp_Object length;
+  int len;
+  Lisp_Object *faces;
+  int j;
+
+  if (CONSP (prop)
+      && ! STRINGP (XCONS (prop)->cdr))
     {
-      /* We have a list of faces, merge them in reverse order */
-      Lisp_Object length;
-      int len;
-      Lisp_Object *faces;
+      /* We have a list of faces, merge them in reverse order.  */
 
       length = Fsafe_length (prop);
       len = XFASTINT (length);
 
-      /* Put them into an array */
+      /* Put them into an array */
       faces = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
       for (j = 0; j < len; j++)
        {
          faces[j] = Fcar (prop);
          prop = Fcdr (prop);
        }
-      /* So that we can merge them in the reverse order */
-      for (j = len - 1; j >= 0; j--)
-       {
-         facecode = face_name_id_number (f, faces[j]);
-         if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
-             && FRAME_PARAM_FACES (f) [facecode] != 0)
-           merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
-       }
+      /* So that we can merge them in the reverse order.  */
     }
-  else if (!NILP (prop))
+  else
     {
-      facecode = face_name_id_number (f, prop);
-      if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
-         && FRAME_PARAM_FACES (f) [facecode] != 0)
-       merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
+      faces = (Lisp_Object *) alloca (sizeof (Lisp_Object));
+      faces[0] = prop;
+      len = 1;
     }
 
-  noverlays = sort_overlays (overlay_vec, noverlays, w);
-
-  /* Now merge the overlay data in that order.  */
-  for (i = 0; i < noverlays; i++)
+  for (j = len - 1; j >= 0; j--)
     {
-      prop = Foverlay_get (overlay_vec[i], propname);
-      if (CONSP (prop))
+      if (CONSP (faces[j]))
        {
-         /* We have a list of faces, merge them in reverse order */
-         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++)
-           {
-             faces[j] = Fcar (prop);
-             prop = Fcdr (prop);
-           }
-         /* So that we can merge them in the reverse order */
-         for (j = len - 1; j >= 0; j--)
-           {
-             facecode = face_name_id_number (f, faces[j]);
-             if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
-                 && FRAME_PARAM_FACES (f) [facecode] != 0)
-               merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
-           }
+         if (EQ (XCONS (faces[j])->car, Qbackground_color))
+           face->background = load_color (f, XCONS (faces[j])->cdr);
+         if (EQ (XCONS (faces[j])->car, Qforeground_color))
+           face->foreground = load_color (f, XCONS (faces[j])->cdr);
        }
-      else if (!NILP (prop))
+      else
        {
-         Lisp_Object oend;
-         int oendpos;
-
-         facecode = face_name_id_number (f, prop);
+         int facecode = face_name_id_number (f, faces[j]);
          if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
              && FRAME_PARAM_FACES (f) [facecode] != 0)
-           merge_faces (FRAME_PARAM_FACES (f)[facecode], &face);
-
-         oend = OVERLAY_END (overlay_vec[i]);
-         oendpos = OVERLAY_POSITION (oend);
-         if (oendpos < endpos)
-           endpos = oendpos;
+           merge_faces (FRAME_PARAM_FACES (f) [facecode], face);
        }
     }
-
-  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_PARAM_FACES (f)[region_face], &face);
-    }
-
-  *endptr = endpos;
-
-  return intern_computed_face (f, &face);
 }
+
 \f
 /* Recompute the GC's for the default and modeline faces.
    We call this after changing frame parameters on which those GC's
@@ -1067,10 +1086,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));
 
@@ -1087,26 +1111,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)
@@ -1161,10 +1165,38 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
         is taken to mean an unused face nowadays).  */
       face->font = (XFontStruct *)1 ;
 #else
-      XFontStruct *font = load_font (f, attr_value);
-      if (face->font != f->output_data.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
@@ -1215,19 +1247,13 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
   if (garbaged)
     {
       SET_FRAME_GARBAGED (f);
+#ifdef HAVE_X_WINDOWS
       FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
+#endif
     }
 
   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
@@ -1248,12 +1274,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");
@@ -1266,14 +1322,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 */