XEmacs 21.2.38 (Peisino)
[chise/xemacs-chise.git.1] / src / faces.c
index 417f170..e87d934 100644 (file)
@@ -496,7 +496,7 @@ update_inheritance_mapper_internal (Lisp_Object cur_face,
 }
 
 static int
-update_face_inheritance_mapper (CONST void *hash_key, void *hash_contents,
+update_face_inheritance_mapper (const void *hash_key, void *hash_contents,
                                void *face_inheritance_closure)
 {
   Lisp_Object key, contents;
@@ -596,7 +596,7 @@ face_property_matching_instance (Lisp_Object face, Lisp_Object property,
 
 \f
 DEFUN ("facep", Ffacep, 1, 1, 0, /*
-Return non-nil if OBJECT is a face.
+Return t if OBJECT is a face.
 */
        (object))
 {
@@ -762,8 +762,8 @@ other non-nil value both permanent and temporary are included.
 }
 
 DEFUN ("make-face", Fmake_face, 1, 3, 0, /*
-Define and return a new FACE described by DOC-STRING.
-You can modify the font, color, etc of a face with the set-face-* functions.
+Define a new face with name NAME (a symbol), described by DOC-STRING.
+You can modify the font, color, etc. of a face with the set-face-* functions.
 If the face already exists, it is unmodified.
 If TEMPORARY is non-nil, this face will cease to exist if not in use.
 */
@@ -1154,22 +1154,6 @@ face_cachel_charset_font_metric_info (struct face_cachel *cachel,
     }
 }
 
-/* Called when the updated flag has been cleared on a cachel. */
-
-void
-update_face_cachel_data (struct face_cachel *cachel,
-                        Lisp_Object domain,
-                        Lisp_Object face)
-{
-  if (XFACE (face)->dirty || UNBOUNDP (cachel->face))
-    {
-      int default_face = EQ (face, Vdefault_face);
-      cachel->face = face;
-
-      /* We normally only set the _specified flags if the value was
-         actually bound.  The exception is for the default face where
-         we always set it since it is the ultimate fallback. */
-
 #define FROB(field)                                                         \
   do {                                                                      \
     Lisp_Object new_val =                                                   \
@@ -1188,31 +1172,125 @@ update_face_cachel_data (struct face_cachel *cachel,
     cachel->field##_specified = (bound || default_face);                    \
   } while (0)
 
+/*
+ * A face's background pixmap will override the face's
+ * background color.  But the background pixmap of the
+ * default face should not override the background color of
+ * a face if the background color has been specified or
+ * inherited.
+ *
+ * To accomplish this we remove the background pixmap of the
+ * cachel and mark it as having been specified so that cachel
+ * merging won't override it later.
+ */
+#define MAYBE_UNFROB_BACKGROUND_PIXMAP          \
+do                                              \
+{                                               \
+  if (! default_face                            \
+      && cachel->background_specified           \
+      && ! cachel->background_pixmap_specified) \
+    {                                           \
+      cachel->background_pixmap = Qunbound;     \
+      cachel->background_pixmap_specified = 1;  \
+    }                                           \
+} while (0)
+
+
+/* Add a cachel for the given face to the given window's cache. */
+
+static void
+add_face_cachel (struct window *w, Lisp_Object face)
+{
+  int must_finish_frobbing = ! WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
+  struct face_cachel new_cachel;
+  Lisp_Object domain;
+
+  reset_face_cachel (&new_cachel);
+  XSETWINDOW (domain, w);
+  update_face_cachel_data (&new_cachel, domain, face);
+  Dynarr_add (w->face_cachels, new_cachel);
+
+  /* The face's background pixmap have not yet been frobbed (see comment
+     int update_face_cachel_data), so we have to do it now */
+  if (must_finish_frobbing)
+    {
+      int default_face = EQ (face, Vdefault_face);
+      struct face_cachel *cachel
+       = Dynarr_atp (w->face_cachels, Dynarr_length (w->face_cachels) - 1);
+
+      FROB (background_pixmap);
+      MAYBE_UNFROB_BACKGROUND_PIXMAP;
+    }
+}
+
+/* Called when the updated flag has been cleared on a cachel.
+   This function returns 1 if the caller must finish the update (see comment
+   below), 0 otherwise.
+*/
+
+void
+update_face_cachel_data (struct face_cachel *cachel,
+                        Lisp_Object domain,
+                        Lisp_Object face)
+{
+  if (XFACE (face)->dirty || UNBOUNDP (cachel->face))
+    {
+      int default_face = EQ (face, Vdefault_face);
+      cachel->face = face;
+
+      /* We normally only set the _specified flags if the value was
+         actually bound.  The exception is for the default face where
+         we always set it since it is the ultimate fallback. */
+
       FROB (foreground);
       FROB (background);
       FROB (display_table);
-      FROB (background_pixmap);
 
-      /*
-       * A face's background pixmap will override the face's
-       * background color.  But the background pixmap of the
-       * default face should not override the background color of
-       * a face if the background color has been specified or
-       * inherited.
-       *
-       * To accomplish this we remove the background pixmap of the
-       * cachel and mark it as having been specified so that cachel
-       * merging won't override it later.
-       */
-      if (! default_face
-         && cachel->background_specified
-         && ! cachel->background_pixmap_specified)
+      /* #### WARNING: the background pixmap property of faces is currently
+        the only one dealing with images. The problem we have here is that
+        frobbing the background pixmap might lead to image instantiation
+        which in turn might require that the cache we're building be up to
+        date, hence a crash. Here's a typical scenario of this:
+
+        - a new window is created and it's face cache elements are
+        initialized through a call to reset_face_cachels[1]. At that point,
+        the cache for the default and modeline faces (normaly taken care of
+        by redisplay itself) are null.
+        - the default face has a background pixmap which needs to be
+        instantiated right here, as a consequence of cache initialization.
+        - the background pixmap image happens to be instantiated as a string
+        (this happens on tty's for instance).
+        - In order to do this, we need to compute the string geometry.
+        - In order to do this, we might have to access the window's default
+        face cache. But this is the cache we're building right now, it is
+        null.
+        - BARF !!!!!
+
+        To sum up, this means that it is in general unsafe to instantiate
+        images before face cache updating is complete (appart from image
+        related face attributes). The solution we use below is to actually
+        detect whether we're building the window's face_cachels for the first
+        time, and simply NOT frob the background pixmap in that case. If
+        other image-related face attributes are ever implemented, they should
+        be protected the same way right here.
+
+        One note:
+        * See comment in `default_face_font_info' in face.c. Who wrote it ?
+        Maybe we have the begining of an answer here ?
+
+        Footnotes:
+        [1] See comment at the top of `allocate_window' in window.c.
+
+        -- didier
+      */
+      if (! WINDOWP (domain)
+         || WINDOW_FACE_CACHEL (DOMAIN_XWINDOW (domain), DEFAULT_INDEX))
        {
-         cachel->background_pixmap = Qunbound;
-         cachel->background_pixmap_specified = 1;
+         FROB (background_pixmap);
+         MAYBE_UNFROB_BACKGROUND_PIXMAP;
        }
-
 #undef FROB
+#undef MAYBE_UNFROB_BACKGROUND_PIXMAP
 
       ensure_face_cachel_contains_charset (cachel, domain, Vcharset_ascii);
 
@@ -1317,20 +1395,6 @@ reset_face_cachel (struct face_cachel *cachel)
   cachel->background_pixmap = Qunbound;
 }
 
-/* Add a cachel for the given face to the given window's cache. */
-
-static void
-add_face_cachel (struct window *w, Lisp_Object face)
-{
-  struct face_cachel new_cachel;
-  Lisp_Object window;
-
-  reset_face_cachel (&new_cachel);
-  XSETWINDOW (window, w);
-  update_face_cachel_data (&new_cachel, window, face);
-  Dynarr_add (w->face_cachels, new_cachel);
-}
-
 /* Retrieve the index to a cachel for window W that corresponds to
    the specified face.  If necessary, add a new element to the
    cache. */
@@ -1575,7 +1639,16 @@ get_extent_fragment_face_cache_index (struct window *w,
       findex = get_builtin_face_cache_index (w, Vdefault_face);
       merge_face_cachel_data (w, findex, &cachel);
 
-      return get_merged_face_cache_index (w, &cachel);
+      findex = get_merged_face_cache_index (w, &cachel);
+      if (cachel.merged_faces &&
+         /* merged_faces did not get stored and available via return value */
+         Dynarr_at (w->face_cachels, findex).merged_faces !=
+         cachel.merged_faces)
+       {
+         Dynarr_free (cachel.merged_faces);
+         cachel.merged_faces = 0;
+       }
+      return findex;
     }
 }
 
@@ -1752,6 +1825,8 @@ LOCALE, TAG-SET, EXACT-P, and HOW-TO-ADD are as in `copy-specifier'.
 void
 syms_of_faces (void)
 {
+  INIT_LRECORD_IMPLEMENTATION (face);
+
   /* Qdefault, Qwidget, Qleft_margin, Qright_margin defined in general.c */
   defsymbol (&Qmodeline, "modeline");
   defsymbol (&Qgui_element, "gui-element");
@@ -1894,7 +1969,7 @@ complex_vars_of_faces (void)
        (#### Perhaps we should remove the stuff from x-faces.el
        and only depend on this stuff here?  That should work.)
      */
-    CONST char *fonts[] =
+    const char *fonts[] =
     {
       "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*",
       "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*",
@@ -1912,7 +1987,7 @@ complex_vars_of_faces (void)
       "-*-*-*-*-*-*-*-120-*-*-*-*-*-*",
       "*"
     };
-    CONST char **fontptr;
+    const char **fontptr;
 
     for (fontptr = fonts + countof(fonts) - 1; fontptr >= fonts; fontptr--)
       inst_list = Fcons (Fcons (list1 (Qx), build_string (*fontptr)),
@@ -2028,13 +2103,13 @@ complex_vars_of_faces (void)
   Vwidget_face = Fmake_face (Qwidget,
                             build_string ("widget face"),
                             Qnil);
+  set_specifier_fallback (Fget (Vwidget_face, Qfont, Qunbound),
+                         Fget (Vgui_element_face, Qfont, Qunbound));
   set_specifier_fallback (Fget (Vwidget_face, Qforeground, Qunbound),
                          Fget (Vgui_element_face, Qforeground, Qunbound));
   set_specifier_fallback (Fget (Vwidget_face, Qbackground, Qunbound),
                          Fget (Vgui_element_face, Qbackground, Qunbound));
-  set_specifier_fallback (Fget (Vwidget_face, Qbackground_pixmap, Qnil),
-                         Fget (Vgui_element_face, Qbackground_pixmap,
-                               Qunbound));
+  /* We don't want widgets to have a default background pixmap. */
 
   Vleft_margin_face = Fmake_face (Qleft_margin,
                                  build_string ("left margin face"),