X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a4eec62604216f6d4efc86221466a5e883a0113b..5dcde606e32d1794f8268ea51cd2d1746e45a311:/src/xfaces.c diff --git a/src/xfaces.c b/src/xfaces.c index 3afa17a1c2..6bde1c121d 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1,6 +1,6 @@ /* xfaces.c -- "Face" primitives. Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -27,34 +27,36 @@ along with GNU Emacs. If not, see . */ 1. Font family name. - 2. Relative proportionate width, aka character set width or set + 2. Font foundary name. + + 3. Relative proportionate width, aka character set width or set width (swidth), e.g. `semi-compressed'. - 3. Font height in 1/10pt. + 4. Font height in 1/10pt. - 4. Font weight, e.g. `bold'. + 5. Font weight, e.g. `bold'. - 5. Font slant, e.g. `italic'. + 6. Font slant, e.g. `italic'. - 6. Foreground color. + 7. Foreground color. - 7. Background color. + 8. Background color. - 8. Whether or not characters should be underlined, and in what color. + 9. Whether or not characters should be underlined, and in what color. - 9. Whether or not characters should be displayed in inverse video. + 10. Whether or not characters should be displayed in inverse video. - 10. A background stipple, a bitmap. + 11. A background stipple, a bitmap. - 11. Whether or not characters should be overlined, and in what color. + 12. Whether or not characters should be overlined, and in what color. - 12. Whether or not characters should be strike-through, and in what + 13. Whether or not characters should be strike-through, and in what color. - 13. Whether or not a box should be drawn around characters, the box + 14. Whether or not a box should be drawn around characters, the box type, and, for simple boxes, in what color. - 14. Font-spec, or nil. This is a special attribute. + 15. Font-spec, or nil. This is a special attribute. A font-spec is a collection of font attributes (specs). @@ -202,6 +204,7 @@ along with GNU Emacs. If not, see . */ #include #include #include /* This needs to be before termchar.h */ +#include #include "lisp.h" #include "character.h" @@ -232,15 +235,18 @@ along with GNU Emacs. If not, see . */ #define x_display_info w32_display_info #define FRAME_X_FONT_TABLE FRAME_W32_FONT_TABLE #define check_x check_w32 -#define x_list_fonts w32_list_fonts #define GCGraphicsExposures 0 #endif /* WINDOWSNT */ -#ifdef MAC_OS -#include "macterm.h" -#define x_display_info mac_display_info -#define check_x check_mac -#endif /* MAC_OS */ +#ifdef HAVE_NS +#include "nsterm.h" +#undef FRAME_X_DISPLAY_INFO +#define FRAME_X_DISPLAY_INFO FRAME_NS_DISPLAY_INFO +#define x_display_info ns_display_info +#define FRAME_X_FONT_TABLE FRAME_NS_FONT_TABLE +#define check_x check_ns +#define GCGraphicsExposures 0 +#endif /* HAVE_NS */ #include "buffer.h" #include "dispextern.h" @@ -422,6 +428,23 @@ Lisp_Object Qbitmap_spec_p; Lisp_Object Vface_new_frame_defaults; +/* Alist of face remappings. Each element is of the form: + (FACE REPLACEMENT...) which causes display of the face FACE to use + REPLACEMENT... instead. REPLACEMENT... is interpreted the same way + the value of a `face' text property is: it may be (1) A face name, + (2) A list of face names, (3) A property-list of face attribute/value + pairs, or (4) A list of face names intermixed with lists containing + face attribute/value pairs. + + Multiple entries in REPLACEMENT... are merged together to form the final + result, with faces or attributes earlier in the list taking precedence + over those that are later. + + Face-name remapping cycles are suppressed; recursive references use + the underlying face instead of the remapped face. */ + +Lisp_Object Vface_remapping_alist; + /* The next ID to assign to Lisp faces. */ static int next_lface_id; @@ -484,7 +507,6 @@ int menu_face_changed_default; /* Function prototypes. */ -struct font_name; struct table_entry; struct named_merge_point; @@ -493,9 +515,9 @@ static void map_tty_color P_ ((struct frame *, struct face *, 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 get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, int)); +static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, + int, struct named_merge_point *)); static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *)); -static unsigned char *xstrlwr P_ ((unsigned char *)); static struct frame *frame_or_selected_frame P_ ((Lisp_Object, int)); static void load_face_colors P_ ((struct frame *, struct face *, Lisp_Object *)); static void free_face_colors P_ ((struct frame *, struct face *)); @@ -534,10 +556,6 @@ static void uncache_face P_ ((struct face_cache *, struct face *)); static GC x_create_gc P_ ((struct frame *, unsigned long, XGCValues *)); static void x_free_gc P_ ((struct frame *, GC)); -#ifdef WINDOWSNT -extern Lisp_Object w32_list_fonts P_ ((struct frame *, Lisp_Object, int, int)); -#endif /* WINDOWSNT */ - #ifdef USE_X_TOOLKIT static void x_update_menu_appearance P_ ((struct frame *)); @@ -748,8 +766,8 @@ x_free_gc (f, gc) #endif /* WINDOWSNT */ -#ifdef MAC_OS -/* Mac OS emulation of GCs */ +#ifdef HAVE_NS +/* NS emulation of GCs */ static INLINE GC x_create_gc (f, mask, xgcv) @@ -757,11 +775,9 @@ x_create_gc (f, mask, xgcv) unsigned long mask; XGCValues *xgcv; { - GC gc; - BLOCK_INPUT; - gc = XCreateGC (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), mask, xgcv); - UNBLOCK_INPUT; - IF_DEBUG (++ngcs); + GC gc = xmalloc (sizeof (*gc)); + if (gc) + bcopy(xgcv, gc, sizeof(XGCValues)); return gc; } @@ -770,12 +786,9 @@ x_free_gc (f, gc) struct frame *f; GC gc; { - eassert (interrupt_input_blocked); - IF_DEBUG (xassert (--ngcs >= 0)); - XFreeGC (FRAME_MAC_DISPLAY (f), gc); + xfree (gc); } - -#endif /* MAC_OS */ +#endif /* HAVE_NS */ /* Like strcasecmp/stricmp. Used to compare parts of font names which are in ISO8859-1. */ @@ -836,8 +849,10 @@ init_frame_faces (f) /* Make the image cache. */ if (FRAME_WINDOW_P (f)) { + /* We initialize the image cache when creating the first frame + on a terminal, and not during terminal creation. This way, + `x-open-connection' on a tty won't create an image cache. */ if (FRAME_IMAGE_CACHE (f) == NULL) - /* Is that ever possible?? --Stef */ FRAME_IMAGE_CACHE (f) = make_image_cache (); ++FRAME_IMAGE_CACHE (f)->refcount; } @@ -851,15 +866,15 @@ init_frame_faces (f) #ifdef WINDOWSNT if (!FRAME_WINDOW_P (f) || FRAME_W32_WINDOW (f)) #endif -#ifdef MAC_OS - if (!FRAME_MAC_P (f) || FRAME_MAC_WINDOW (f)) +#ifdef HAVE_NS + if (!FRAME_NS_P (f) || FRAME_NS_WINDOW (f)) #endif if (!realize_basic_faces (f)) - abort (); + abort (); } -/* Free face cache of frame F. Called from Fdelete_frame. */ +/* Free face cache of frame F. Called from delete_frame. */ void free_frame_faces (f) @@ -1247,9 +1262,9 @@ defined_color (f, color_name, color_def, alloc) else if (FRAME_W32_P (f)) return w32_defined_color (f, color_name, color_def, alloc); #endif -#ifdef MAC_OS - else if (FRAME_MAC_P (f)) - return mac_defined_color (f, color_name, color_def, alloc); +#ifdef HAVE_NS + else if (FRAME_NS_P (f)) + return ns_defined_color (f, color_name, color_def, alloc, 1); #endif else abort (); @@ -1540,6 +1555,7 @@ free_face_colors (f, face) struct frame *f; struct face *face; { +/* PENDING(NS): need to do something here? */ #ifdef HAVE_X_WINDOWS if (face->colors_copied_bitwise_p) return; @@ -1670,35 +1686,10 @@ enum xlfd_swidth font height, then for weight, then for slant.' This variable can be set via set-face-font-sort-order. */ -#ifdef MAC_OS -static int font_sort_order[4] = { - XLFD_SWIDTH, XLFD_POINT_SIZE, XLFD_WEIGHT, XLFD_SLANT -}; -#else static int font_sort_order[4]; -#endif - #ifdef HAVE_WINDOW_SYSTEM -/* Return a rescaling ratio of a font of NAME. */ - -static double -font_rescale_ratio (name) - char *name; -{ - Lisp_Object tail, elt; - - for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail)) - { - elt = XCAR (tail); - if (STRINGP (XCAR (elt)) && FLOATP (XCDR (elt)) - && fast_c_string_match_ignore_case (XCAR (elt), name) >= 0) - return XFLOAT_DATA (XCDR (elt)); - } - return 1.0; -} - static enum font_property_index font_props_for_sorting[FONT_SIZE_INDEX]; static int @@ -1708,7 +1699,7 @@ compare_fonts_by_sort_order (v1, v2) Lisp_Object font1 = *(Lisp_Object *) v1; Lisp_Object font2 = *(Lisp_Object *) v2; int i; - + for (i = 0; i < FONT_SIZE_INDEX; i++) { enum font_property_index idx = font_props_for_sorting[i]; @@ -1754,43 +1745,52 @@ the face font sort order. */) (family, frame) Lisp_Object family, frame; { - struct frame *f = check_x_frame (frame); - Lisp_Object font_spec = Qnil, vec; - int i, nfonts; + Lisp_Object font_spec, list, *drivers, vec; + int i, nfonts, ndrivers; Lisp_Object result; + if (NILP (frame)) + frame = selected_frame; + CHECK_LIVE_FRAME (frame); + + font_spec = Ffont_spec (0, NULL); if (!NILP (family)) { CHECK_STRING (family); - font_spec = Ffont_spec (0, NULL); - Ffont_put (font_spec, QCfamily, family); + font_parse_family_registry (family, Qnil, font_spec); } - vec = font_list_entities (frame, font_spec); - nfonts = ASIZE (vec); - if (nfonts == 0) + + list = font_list_entities (frame, font_spec); + if (NILP (list)) return Qnil; - if (nfonts > 1) - { - for (i = 0; i < 4; i++) - switch (font_sort_order[i]) - { - case XLFD_SWIDTH: - font_props_for_sorting[i] = FONT_WIDTH_INDEX; break; - case XLFD_POINT_SIZE: - font_props_for_sorting[i] = FONT_SIZE_INDEX; break; - case XLFD_WEIGHT: - font_props_for_sorting[i] = FONT_WEIGHT_INDEX; break; - default: - font_props_for_sorting[i] = FONT_SLANT_INDEX; break; - } - font_props_for_sorting[i++] = FONT_FAMILY_INDEX; - font_props_for_sorting[i++] = FONT_FOUNDRY_INDEX; - font_props_for_sorting[i++] = FONT_ADSTYLE_INDEX; - font_props_for_sorting[i++] = FONT_REGISTRY_INDEX; - qsort (XVECTOR (vec)->contents, nfonts, sizeof (Lisp_Object), - compare_fonts_by_sort_order); - } + /* Sort the font entities. */ + for (i = 0; i < 4; i++) + switch (font_sort_order[i]) + { + case XLFD_SWIDTH: + font_props_for_sorting[i] = FONT_WIDTH_INDEX; break; + case XLFD_POINT_SIZE: + font_props_for_sorting[i] = FONT_SIZE_INDEX; break; + case XLFD_WEIGHT: + font_props_for_sorting[i] = FONT_WEIGHT_INDEX; break; + default: + font_props_for_sorting[i] = FONT_SLANT_INDEX; break; + } + font_props_for_sorting[i++] = FONT_FAMILY_INDEX; + font_props_for_sorting[i++] = FONT_FOUNDRY_INDEX; + font_props_for_sorting[i++] = FONT_ADSTYLE_INDEX; + font_props_for_sorting[i++] = FONT_REGISTRY_INDEX; + + ndrivers = XINT (Flength (list)); + drivers = alloca (sizeof (Lisp_Object) * ndrivers); + for (i = 0; i < ndrivers; i++, list = XCDR (list)) + drivers[i] = XCAR (list); + vec = Fvconcat (ndrivers, drivers); + nfonts = ASIZE (vec); + + qsort (XVECTOR (vec)->contents, nfonts, sizeof (Lisp_Object), + compare_fonts_by_sort_order); result = Qnil; for (i = nfonts - 1; i >= 0; --i) @@ -1803,13 +1803,13 @@ the face font sort order. */) ASET (v, 0, AREF (font, FONT_FAMILY_INDEX)); ASET (v, 1, FONT_WIDTH_SYMBOLIC (font)); point = PIXEL_TO_POINT (XINT (AREF (font, FONT_SIZE_INDEX)) * 10, - f->resy); + XFRAME (frame)->resy); ASET (v, 2, make_number (point)); ASET (v, 3, FONT_WEIGHT_SYMBOLIC (font)); ASET (v, 4, FONT_SLANT_SYMBOLIC (font)); spacing = Ffont_get (font, QCspacing); ASET (v, 5, (NILP (spacing) || EQ (spacing, Qp)) ? Qnil : Qt); - ASET (v, 6, AREF (font, FONT_NAME_INDEX)); + ASET (v, 6, Ffont_xlfd_name (font, Qnil)); ASET (v, 7, AREF (font, FONT_REGISTRY_INDEX)); result = Fcons (v, result); @@ -1818,33 +1818,20 @@ the face font sort order. */) return result; } - -DEFUN ("x-font-family-list", Fx_font_family_list, Sx_font_family_list, - 0, 1, 0, - doc: /* Return a list of available font families on FRAME. -If FRAME is omitted or nil, use the selected frame. -Value is a list of conses (FAMILY . FIXED-P) where FAMILY -is a font family, and FIXED-P is non-nil if fonts of that family -are fixed-pitch. */) - (frame) - Lisp_Object frame; -{ - return Ffont_family_list (frame); -} - - DEFUN ("x-list-fonts", Fx_list_fonts, Sx_list_fonts, 1, 5, 0, doc: /* Return a list of the names of available fonts matching PATTERN. If optional arguments FACE and FRAME are specified, return only fonts the same size as FACE on FRAME. -PATTERN is a string, perhaps with wildcard characters; + +PATTERN should be a string containing a font name in the XLFD, +Fontconfig, or GTK format. A font name given in the XLFD format may +contain wildcard characters: the * character matches any substring, and the ? character matches any single character. PATTERN is case-insensitive. -FACE is a face name--a symbol. The return value is a list of strings, suitable as arguments to -set-face-font. +`set-face-font'. Fonts Emacs can't use may or may not be excluded even if they match PATTERN and FACE. @@ -1913,14 +1900,32 @@ the WIDTH times as wide as FACE on FRAME. */) Lisp_Object args[2], tail; font_spec = font_spec_from_name (pattern); + if (!FONTP (font_spec)) + signal_error ("Invalid font name", pattern); + if (size) { Ffont_put (font_spec, QCsize, make_number (size)); Ffont_put (font_spec, QCavgwidth, make_number (avgwidth)); } - args[0] = Flist_fonts (font_spec, frame, maximum, Qnil); + args[0] = Flist_fonts (font_spec, frame, maximum, font_spec); for (tail = args[0]; CONSP (tail); tail = XCDR (tail)) - XSETCAR (tail, Ffont_xlfd_name (XCAR (tail), Qnil)); + { + Lisp_Object font_entity; + + font_entity = XCAR (tail); + if ((NILP (AREF (font_entity, FONT_SIZE_INDEX)) + || XINT (AREF (font_entity, FONT_SIZE_INDEX)) == 0) + && ! NILP (AREF (font_spec, FONT_SIZE_INDEX))) + { + /* This is a scalable font. For backward compatibility, + we set the specified size. */ + font_entity = Fcopy_font_spec (font_entity); + ASET (font_entity, FONT_SIZE_INDEX, + AREF (font_spec, FONT_SIZE_INDEX)); + } + XSETCAR (tail, Ffont_xlfd_name (font_entity, Qnil)); + } if (NILP (frame)) /* We don't have to check fontsets. */ return args[0]; @@ -1931,7 +1936,6 @@ the WIDTH times as wide as FACE on FRAME. */) #endif /* HAVE_WINDOW_SYSTEM */ - /*********************************************************************** Lisp Faces @@ -1940,6 +1944,7 @@ the WIDTH times as wide as FACE on FRAME. */) /* Access face attributes of face LFACE, a Lisp vector. */ #define LFACE_FAMILY(LFACE) AREF ((LFACE), LFACE_FAMILY_INDEX) +#define LFACE_FOUNDRY(LFACE) AREF ((LFACE), LFACE_FOUNDRY_INDEX) #define LFACE_HEIGHT(LFACE) AREF ((LFACE), LFACE_HEIGHT_INDEX) #define LFACE_WEIGHT(LFACE) AREF ((LFACE), LFACE_WEIGHT_INDEX) #define LFACE_SLANT(LFACE) AREF ((LFACE), LFACE_SLANT_INDEX) @@ -1976,6 +1981,9 @@ check_lface_attrs (attrs) xassert (UNSPECIFIEDP (attrs[LFACE_FAMILY_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_FAMILY_INDEX]) || STRINGP (attrs[LFACE_FAMILY_INDEX])); + xassert (UNSPECIFIEDP (attrs[LFACE_FOUNDRY_INDEX]) + || IGNORE_DEFFACE_P (attrs[LFACE_FOUNDRY_INDEX]) + || STRINGP (attrs[LFACE_FOUNDRY_INDEX])); xassert (UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_SWIDTH_INDEX]) || SYMBOLP (attrs[LFACE_SWIDTH_INDEX])); @@ -2060,6 +2068,12 @@ check_lface (lface) /* Face-merge cycle checking. */ +enum named_merge_point_kind +{ + NAMED_MERGE_POINT_NORMAL, + NAMED_MERGE_POINT_REMAP +}; + /* A `named merge point' is simply a point during face-merging where we look up a face by name. We keep a stack of which named lookups we're currently processing so that we can easily detect cycles, using a @@ -2069,27 +2083,40 @@ check_lface (lface) struct named_merge_point { Lisp_Object face_name; + enum named_merge_point_kind named_merge_point_kind; struct named_merge_point *prev; }; /* If a face merging cycle is detected for FACE_NAME, return 0, otherwise add NEW_NAMED_MERGE_POINT, which is initialized using - FACE_NAME, as the head of the linked list pointed to by - NAMED_MERGE_POINTS, and return 1. */ + FACE_NAME and NAMED_MERGE_POINT_KIND, as the head of the linked list + pointed to by NAMED_MERGE_POINTS, and return 1. */ static INLINE int push_named_merge_point (struct named_merge_point *new_named_merge_point, Lisp_Object face_name, + enum named_merge_point_kind named_merge_point_kind, struct named_merge_point **named_merge_points) { struct named_merge_point *prev; for (prev = *named_merge_points; prev; prev = prev->prev) if (EQ (face_name, prev->face_name)) - return 0; + { + if (prev->named_merge_point_kind == named_merge_point_kind) + /* A cycle, so fail. */ + return 0; + else if (prev->named_merge_point_kind == NAMED_MERGE_POINT_REMAP) + /* A remap `hides ' any previous normal merge points + (because the remap means that it's actually different face), + so as we know the current merge point must be normal, we + can just assume it's OK. */ + break; + } new_named_merge_point->face_name = face_name; + new_named_merge_point->named_merge_point_kind = named_merge_point_kind; new_named_merge_point->prev = *named_merge_points; *named_merge_points = new_named_merge_point; @@ -2167,22 +2194,17 @@ resolve_face_name (face_name, signal_p) /* Return the face definition of FACE_NAME on frame F. F null means return the definition for new frames. FACE_NAME may be a string or a symbol (apparently Emacs 20.2 allowed strings as face names in - face text properties; Ediff uses that). If FACE_NAME is an alias - for another face, return that face's definition. If SIGNAL_P is - non-zero, signal an error if FACE_NAME is not a valid face name. - If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face - name. */ - + face text properties; Ediff uses that). If SIGNAL_P is non-zero, + signal an error if FACE_NAME is not a valid face name. If SIGNAL_P + is zero, value is nil if FACE_NAME is not a valid face name. */ static INLINE Lisp_Object -lface_from_face_name (f, face_name, signal_p) +lface_from_face_name_no_resolve (f, face_name, signal_p) struct frame *f; Lisp_Object face_name; int signal_p; { Lisp_Object lface; - face_name = resolve_face_name (face_name, signal_p); - if (f) lface = assq_no_quit (face_name, f->face_alist); else @@ -2194,9 +2216,28 @@ lface_from_face_name (f, face_name, signal_p) signal_error ("Invalid face", face_name); check_lface (lface); + return lface; } +/* Return the face definition of FACE_NAME on frame F. F null means + return the definition for new frames. FACE_NAME may be a string or + a symbol (apparently Emacs 20.2 allowed strings as face names in + face text properties; Ediff uses that). If FACE_NAME is an alias + for another face, return that face's definition. If SIGNAL_P is + non-zero, signal an error if FACE_NAME is not a valid face name. + If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face + name. */ +static INLINE Lisp_Object +lface_from_face_name (f, face_name, signal_p) + struct frame *f; + Lisp_Object face_name; + int signal_p; +{ + face_name = resolve_face_name (face_name, signal_p); + return lface_from_face_name_no_resolve (f, face_name, signal_p); +} + /* Get face attributes of face FACE_NAME from frame-local faces on frame F. Store the resulting attributes in ATTRS which must point @@ -2205,26 +2246,65 @@ lface_from_face_name (f, face_name, signal_p) Otherwise, value is zero if FACE_NAME is not a face. */ static INLINE int -get_lface_attributes (f, face_name, attrs, signal_p) +get_lface_attributes_no_remap (f, face_name, attrs, signal_p) struct frame *f; Lisp_Object face_name; Lisp_Object *attrs; int signal_p; { Lisp_Object lface; - int success_p; - lface = lface_from_face_name (f, face_name, signal_p); - if (!NILP (lface)) + lface = lface_from_face_name_no_resolve (f, face_name, signal_p); + + if (! NILP (lface)) + bcopy (XVECTOR (lface)->contents, attrs, + LFACE_VECTOR_SIZE * sizeof *attrs); + + return !NILP (lface); +} + +/* Get face attributes of face FACE_NAME from frame-local faces on frame + F. Store the resulting attributes in ATTRS which must point to a + vector of Lisp_Objects of size LFACE_VECTOR_SIZE. If FACE_NAME is an + alias for another face, use that face's definition. If SIGNAL_P is + non-zero, signal an error if FACE_NAME does not name a face. + Otherwise, value is zero if FACE_NAME is not a face. */ + +static INLINE int +get_lface_attributes (f, face_name, attrs, signal_p, named_merge_points) + struct frame *f; + Lisp_Object face_name; + Lisp_Object *attrs; + int signal_p; + struct named_merge_point *named_merge_points; +{ + Lisp_Object face_remapping; + + face_name = resolve_face_name (face_name, signal_p); + + /* See if SYMBOL has been remapped to some other face (usually this + is done buffer-locally). */ + face_remapping = assq_no_quit (face_name, Vface_remapping_alist); + if (CONSP (face_remapping)) { - bcopy (XVECTOR (lface)->contents, attrs, - LFACE_VECTOR_SIZE * sizeof *attrs); - success_p = 1; + struct named_merge_point named_merge_point; + + if (push_named_merge_point (&named_merge_point, + face_name, NAMED_MERGE_POINT_REMAP, + &named_merge_points)) + { + int i; + + for (i = 1; i < LFACE_VECTOR_SIZE; ++i) + attrs[i] = Qunspecified; + + return merge_face_ref (f, XCDR (face_remapping), attrs, + signal_p, named_merge_points); + } } - else - success_p = 0; - return success_p; + /* Default case, no remapping. */ + return get_lface_attributes_no_remap (f, face_name, attrs, signal_p); } @@ -2239,13 +2319,7 @@ lface_fully_specified_p (attrs) for (i = 1; i < LFACE_VECTOR_SIZE; ++i) if (i != LFACE_FONT_INDEX && i != LFACE_INHERIT_INDEX) - if ((UNSPECIFIEDP (attrs[i]) || IGNORE_DEFFACE_P (attrs[i])) -#ifdef MAC_OS - /* MAC_TODO: No stipple support on Mac OS yet, this index is - always unspecified. */ - && i != LFACE_STIPPLE_INDEX -#endif - ) + if ((UNSPECIFIEDP (attrs[i]) || IGNORE_DEFFACE_P (attrs[i]))) break; return i == LFACE_VECTOR_SIZE; @@ -2273,25 +2347,16 @@ set_lface_from_font (f, lface, font_object, force_p) if (force_p || UNSPECIFIEDP (LFACE_FAMILY (lface))) { - Lisp_Object foundry = AREF (font_object, FONT_FOUNDRY_INDEX); Lisp_Object family = AREF (font_object, FONT_FAMILY_INDEX); - if (! NILP (foundry)) - { - if (! NILP (family)) - val = concat3 (SYMBOL_NAME (foundry), build_string ("-"), - SYMBOL_NAME (family)); - else - val = concat2 (SYMBOL_NAME (foundry), build_string ("-*")); - } - else - { - if (! NILP (family)) - val = SYMBOL_NAME (family); - else - val = build_string ("*"); - } - LFACE_FAMILY (lface) = val; + LFACE_FAMILY (lface) = SYMBOL_NAME (family); + } + + if (force_p || UNSPECIFIEDP (LFACE_FOUNDRY (lface))) + { + Lisp_Object foundry = AREF (font_object, FONT_FOUNDRY_INDEX); + + LFACE_FOUNDRY (lface) = SYMBOL_NAME (foundry); } if (force_p || UNSPECIFIEDP (LFACE_HEIGHT (lface))) @@ -2329,9 +2394,7 @@ set_lface_from_font (f, lface, font_object, force_p) merged height. If FROM is an invalid height, then INVALID is returned instead. FROM and TO may be either absolute face heights or `relative' heights; the returned value is always an absolute height - unless both FROM and TO are relative. GCPRO is a lisp value that - will be protected from garbage-collection if this function makes a - call into lisp. */ + unless both FROM and TO are relative. */ Lisp_Object merge_face_heights (from, to, invalid) @@ -2380,8 +2443,8 @@ merge_face_heights (from, to, invalid) specified attribute of FROM overrides the corresponding attribute of TO; relative attributes in FROM are merged with the absolute value in TO and replace it. NAMED_MERGE_POINTS is used internally to detect - loops in face inheritance; it should be 0 when called from other - places. */ + loops in face inheritance/remapping; it should be 0 when called from + other places. */ static INLINE void merge_face_vectors (f, from, to, named_merge_points) @@ -2407,6 +2470,16 @@ merge_face_vectors (f, from, to, named_merge_points) to[i] = Fmerge_font_spec (from[i], to[i]); else to[i] = Fcopy_font_spec (from[i]); + if (! NILP (AREF (to[i], FONT_FOUNDRY_INDEX))) + to[LFACE_FOUNDRY_INDEX] = SYMBOL_NAME (AREF (to[i], FONT_FOUNDRY_INDEX)); + if (! NILP (AREF (to[i], FONT_FAMILY_INDEX))) + to[LFACE_FAMILY_INDEX] = SYMBOL_NAME (AREF (to[i], FONT_FAMILY_INDEX)); + if (! NILP (AREF (to[i], FONT_WEIGHT_INDEX))) + to[LFACE_WEIGHT_INDEX] = FONT_WEIGHT_FOR_FACE (to[i]); + if (! NILP (AREF (to[i], FONT_SLANT_INDEX))) + to[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (to[i]); + if (! NILP (AREF (to[i], FONT_WIDTH_INDEX))) + to[LFACE_SWIDTH_INDEX] = FONT_WIDTH_FOR_FACE (to[i]); ASET (to[i], FONT_SIZE_INDEX, Qnil); } @@ -2418,12 +2491,14 @@ merge_face_vectors (f, from, to, named_merge_points) to[i] = merge_face_heights (from[i], to[i], to[i]); font_clear_prop (to, FONT_SIZE_INDEX); } - else if (i != LFACE_FONT_INDEX) + else if (i != LFACE_FONT_INDEX + && ! EQ (to[i], from[i])) { to[i] = from[i]; if (i >= LFACE_FAMILY_INDEX && i <=LFACE_SLANT_INDEX) font_clear_prop (to, (i == LFACE_FAMILY_INDEX ? FONT_FAMILY_INDEX + : i == LFACE_FOUNDRY_INDEX ? FONT_FOUNDRY_INDEX : i == LFACE_SWIDTH_INDEX ? FONT_WIDTH_INDEX : i == LFACE_HEIGHT_INDEX ? FONT_SIZE_INDEX : i == LFACE_WEIGHT_INDEX ? FONT_WEIGHT_INDEX @@ -2431,11 +2506,6 @@ merge_face_vectors (f, from, to, named_merge_points) } } - /* If `font' attribute is specified, reflect the font properties in - it to the other attributes. */ - if (0 && !UNSPECIFIEDP (to[LFACE_FONT_INDEX])) - font_update_lface (f, to); - /* TO is always an absolute face, which should inherit from nothing. We blindly copy the :inherit attribute above and fix it up here. */ to[LFACE_INHERIT_INDEX] = Qnil; @@ -2456,11 +2526,12 @@ merge_named_face (f, face_name, to, named_merge_points) struct named_merge_point named_merge_point; if (push_named_merge_point (&named_merge_point, - face_name, &named_merge_points)) + face_name, NAMED_MERGE_POINT_NORMAL, + &named_merge_points)) { struct gcpro gcpro1; Lisp_Object from[LFACE_VECTOR_SIZE]; - int ok = get_lface_attributes (f, face_name, from, 0); + int ok = get_lface_attributes (f, face_name, from, 0, named_merge_points); if (ok) { @@ -2558,6 +2629,16 @@ merge_face_ref (f, face_ref, to, err_msgs, named_merge_points) else err = 1; } + else if (EQ (keyword, QCfoundry)) + { + if (STRINGP (value)) + { + to[LFACE_FOUNDRY_INDEX] = value; + font_clear_prop (to, FONT_FOUNDRY_INDEX); + } + else + err = 1; + } else if (EQ (keyword, QCheight)) { Lisp_Object new_height = @@ -2654,7 +2735,7 @@ merge_face_ref (f, face_ref, to, err_msgs, named_merge_points) } else if (EQ (keyword, QCstipple)) { -#ifdef HAVE_X_WINDOWS +#if defined(HAVE_X_WINDOWS) || defined(HAVE_NS) Lisp_Object pixmap_p = Fbitmap_spec_p (value); if (!NILP (pixmap_p)) to[LFACE_STIPPLE_INDEX] = value; @@ -2810,6 +2891,7 @@ Value is a vector of face attributes. */) DEFUN ("internal-lisp-face-p", Finternal_lisp_face_p, Sinternal_lisp_face_p, 1, 2, 0, doc: /* Return non-nil if FACE names a face. +FACE should be a symbol or string. If optional second argument FRAME is non-nil, check for the existence of a frame-local face with name FACE on that frame. Otherwise check for the existence of a global face. */) @@ -2838,7 +2920,7 @@ DEFUN ("internal-copy-lisp-face", Finternal_copy_lisp_face, If FRAME is t, copy the global face definition of FROM. Otherwise, copy the frame-local definition of FROM on FRAME. If NEW-FRAME is a frame, copy that data into the frame-local -definition of TO on NEW-FRAME. If NEW-FRAME is nil. +definition of TO on NEW-FRAME. If NEW-FRAME is nil, FRAME controls where the data is copied to. The value is TO. */) @@ -2958,21 +3040,38 @@ FRAME 0 means change the face on all frames, and change the default LFACE_FAMILY (lface) = value; prop_index = FONT_FAMILY_INDEX; } + else if (EQ (attr, QCfoundry)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_STRING (value); + if (SCHARS (value) == 0) + signal_error ("Invalid face foundry", value); + } + old_value = LFACE_FOUNDRY (lface); + LFACE_FOUNDRY (lface) = value; + prop_index = FONT_FOUNDRY_INDEX; + } else if (EQ (attr, QCheight)) { if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) { - Lisp_Object test; - - test = (EQ (face, Qdefault) - ? value - /* 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)); - - if (!INTEGERP (test) || XINT (test) <= 0) - signal_error ("Invalid face height", value); + if (EQ (face, Qdefault)) + { + /* The default face must have an absolute size. */ + if (!INTEGERP (value) || XINT (value) <= 0) + signal_error ("Invalid default face height", value); + } + else + { + /* For non-default faces, do a test merge with a random + height to see if VALUE's ok. */ + Lisp_Object test = merge_face_heights (value, + make_number (10), + Qnil); + if (!INTEGERP (test) || XINT (test) <= 0) + signal_error ("Invalid face height", value); + } } old_value = LFACE_HEIGHT (lface); @@ -3122,6 +3221,9 @@ FRAME 0 means change the face on all frames, and change the default } else if (EQ (attr, QCforeground)) { + /* Compatibility with 20.x. */ + if (NILP (value)) + value = Qunspecified; if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) { /* Don't check for valid color names here because it depends @@ -3136,6 +3238,9 @@ FRAME 0 means change the face on all frames, and change the default } else if (EQ (attr, QCbackground)) { + /* Compatibility with 20.x. */ + if (NILP (value)) + value = Qunspecified; if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) { /* Don't check for valid color names here because it depends @@ -3150,14 +3255,14 @@ FRAME 0 means change the face on all frames, and change the default } else if (EQ (attr, QCstipple)) { -#ifdef HAVE_X_WINDOWS +#if defined(HAVE_X_WINDOWS) || defined(HAVE_NS) if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value) && !NILP (value) && NILP (Fbitmap_spec_p (value))) signal_error ("Invalid stipple attribute", value); old_value = LFACE_STIPPLE (lface); LFACE_STIPPLE (lface) = value; -#endif /* HAVE_X_WINDOWS */ +#endif /* HAVE_X_WINDOWS || HAVE_NS */ } else if (EQ (attr, QCwidth)) { @@ -3185,11 +3290,14 @@ FRAME 0 means change the face on all frames, and change the default { if (STRINGP (value)) { - int fontset = fs_query_fontset (value, 0); + Lisp_Object name = value; + int fontset = fs_query_fontset (name, 0); if (fontset >= 0) - value = fontset_ascii (fontset); - value = font_spec_from_name (value); + name = fontset_ascii (fontset); + value = font_spec_from_name (name); + if (!FONTP (value)) + signal_error ("Invalid font name", name); } else signal_error ("Invalid font or font-spec", value); @@ -3261,12 +3369,15 @@ FRAME 0 means change the face on all frames, and change the default signal_error ("Invalid face attribute name", attr); if (prop_index) - /* If a font-related attribute other than QCfont and QCfontset is - specified, and if the original QCfont attribute has a font - (font-spec or font-object), set the corresponding property in - the font to nil so that the font selector doesn't think that - the attribute is mandatory. */ - font_clear_prop (XVECTOR (lface)->contents, prop_index); + { + /* If a font-related attribute other than QCfont and QCfontset + is specified, and if the original QCfont attribute has a font + (font-spec or font-object), set the corresponding property in + the font to nil so that the font selector doesn't think that + the attribute is mandatory. Also, clear the average + width. */ + font_clear_prop (XVECTOR (lface)->contents, prop_index); + } /* Changing a named face means that all realized faces depending on that face are invalid. Since we cannot tell which realized faces @@ -3389,11 +3500,14 @@ set_font_frame_param (frame, lface) Lisp_Object frame, lface; { struct frame *f = XFRAME (frame); + Lisp_Object font; - if (FRAME_WINDOW_P (f)) + if (FRAME_WINDOW_P (f) + /* Don't do anything if the font is `unspecified'. This can + happen during frame creation. */ + && (font = LFACE_FONT (lface), + ! UNSPECIFIEDP (font))) { - Lisp_Object font = LFACE_FONT (lface); - if (FONT_SPEC_P (font)) { font = font_load_for_lface (f, XVECTOR (lface)->contents, font); @@ -3438,7 +3552,7 @@ update_face_from_frame_parameter (f, param, new_value) /* Changing the background color might change the background mode, so that we have to load new defface specs. - Call frame-set-background-mode to do that. */ + Call frame-update-face-colors to do that. */ XSETFRAME (frame, f); call1 (Qframe_set_background_mode, frame); @@ -3635,7 +3749,12 @@ x_update_menu_appearance (f) } if (face->font + /* On Solaris 5.8, it's been reported that the `menu' face + can be unspecified here, during startup. Why this + happens remains unknown. -- cyd */ + && FONTP (LFACE_FONT (lface)) && (!UNSPECIFIEDP (LFACE_FAMILY (lface)) + || !UNSPECIFIEDP (LFACE_FOUNDRY (lface)) || !UNSPECIFIEDP (LFACE_SWIDTH (lface)) || !UNSPECIFIEDP (LFACE_WEIGHT (lface)) || !UNSPECIFIEDP (LFACE_SLANT (lface)) @@ -3752,6 +3871,8 @@ frames). If FRAME is omitted or nil, use the selected frame. */) if (EQ (keyword, QCfamily)) value = LFACE_FAMILY (lface); + else if (EQ (keyword, QCfoundry)) + value = LFACE_FOUNDRY (lface); else if (EQ (keyword, QCheight)) value = LFACE_HEIGHT (lface); else if (EQ (keyword, QCweight)) @@ -3827,10 +3948,11 @@ Default face attributes override any local face attributes. */) { int i; Lisp_Object global_lface, local_lface, *gvec, *lvec; + struct frame *f = XFRAME (frame); CHECK_LIVE_FRAME (frame); global_lface = lface_from_face_name (NULL, face, 1); - local_lface = lface_from_face_name (XFRAME (frame), face, 0); + local_lface = lface_from_face_name (f, face, 0); if (NILP (local_lface)) local_lface = Finternal_make_lisp_face (face, frame); @@ -3842,13 +3964,44 @@ Default face attributes override any local face attributes. */) lvec = XVECTOR (local_lface)->contents; gvec = XVECTOR (global_lface)->contents; for (i = 1; i < LFACE_VECTOR_SIZE; ++i) - if (! UNSPECIFIEDP (gvec[i])) - { - if (IGNORE_DEFFACE_P (gvec[i])) - lvec[i] = Qunspecified; - else - lvec[i] = gvec[i]; - } + if (IGNORE_DEFFACE_P (gvec[i])) + lvec[i] = Qunspecified; + else if (! UNSPECIFIEDP (gvec[i])) + lvec[i] = gvec[i]; + + /* If the default face was changed, update the face cache and the + `font' frame parameter. */ + if (EQ (face, Qdefault)) + { + struct face_cache *c = FRAME_FACE_CACHE (f); + struct face *newface, *oldface = FACE_FROM_ID (f, DEFAULT_FACE_ID); + Lisp_Object attrs[LFACE_VECTOR_SIZE]; + + /* This can be NULL (e.g., in batch mode). */ + if (oldface) + { + /* Ensure that the face vector is fully specified by merging + the previously-cached vector. */ + bcopy (oldface->lface, attrs, sizeof attrs); + merge_face_vectors (f, lvec, attrs, 0); + bcopy (attrs, lvec, sizeof attrs); + newface = realize_face (c, lvec, DEFAULT_FACE_ID); + + if ((! UNSPECIFIEDP (gvec[LFACE_FAMILY_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_FOUNDRY_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_HEIGHT_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_WEIGHT_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_SLANT_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_SWIDTH_INDEX]) + || ! UNSPECIFIEDP (gvec[LFACE_FONT_INDEX])) + && newface->font) + { + Lisp_Object name = newface->font->props[FONT_NAME_INDEX]; + Fmodify_frame_parameters (frame, Fcons (Fcons (Qfont, name), + Qnil)); + } + } + } return Qnil; } @@ -3939,7 +4092,7 @@ face_attr_equal_p (v1, v2) return bcmp (SDATA (v1), SDATA (v2), SBYTES (v1)) == 0; - case Lisp_Int: + case_Lisp_Int: case Lisp_Symbol: return 0; @@ -4062,6 +4215,7 @@ lface_hash (v) Lisp_Object *v; { return (hash_string_case_insensitive (v[LFACE_FAMILY_INDEX]) + ^ hash_string_case_insensitive (v[LFACE_FOUNDRY_INDEX]) ^ hash_string_case_insensitive (v[LFACE_FOREGROUND_INDEX]) ^ hash_string_case_insensitive (v[LFACE_BACKGROUND_INDEX]) ^ XHASH (v[LFACE_WEIGHT_INDEX]) @@ -4084,6 +4238,8 @@ lface_same_font_attributes_p (lface1, lface2) && lface_fully_specified_p (lface2)); return (xstrcasecmp (SDATA (lface1[LFACE_FAMILY_INDEX]), SDATA (lface2[LFACE_FAMILY_INDEX])) == 0 + && xstrcasecmp (SDATA (lface1[LFACE_FOUNDRY_INDEX]), + SDATA (lface2[LFACE_FOUNDRY_INDEX])) == 0 && EQ (lface1[LFACE_HEIGHT_INDEX], lface2[LFACE_HEIGHT_INDEX]) && EQ (lface1[LFACE_SWIDTH_INDEX], lface2[LFACE_SWIDTH_INDEX]) && EQ (lface1[LFACE_WEIGHT_INDEX], lface2[LFACE_WEIGHT_INDEX]) @@ -4644,7 +4800,7 @@ lookup_named_face (f, symbol, signal_p) abort (); /* realize_basic_faces must have set it up */ } - if (!get_lface_attributes (f, symbol, symbol_attrs, signal_p)) + if (! get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0)) return -1; bcopy (default_face->lface, attrs, sizeof attrs); @@ -4654,6 +4810,58 @@ lookup_named_face (f, symbol, signal_p) } +/* Return the display face-id of the basic face who's canonical face-id + is FACE_ID. The return value will usually simply be FACE_ID, unless that + basic face has bee remapped via Vface_remapping_alist. This function is + conservative: if something goes wrong, it will simply return FACE_ID + rather than signal an error. */ + +int +lookup_basic_face (f, face_id) + struct frame *f; + int face_id; +{ + Lisp_Object name, mapping; + int remapped_face_id; + + if (NILP (Vface_remapping_alist)) + return face_id; /* Nothing to do. */ + + switch (face_id) + { + case DEFAULT_FACE_ID: name = Qdefault; break; + case MODE_LINE_FACE_ID: name = Qmode_line; break; + case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break; + case HEADER_LINE_FACE_ID: name = Qheader_line; break; + case TOOL_BAR_FACE_ID: name = Qtool_bar; break; + case FRINGE_FACE_ID: name = Qfringe; break; + case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break; + case BORDER_FACE_ID: name = Qborder; break; + case CURSOR_FACE_ID: name = Qcursor; break; + case MOUSE_FACE_ID: name = Qmouse; break; + case MENU_FACE_ID: name = Qmenu; break; + + default: + abort (); /* the caller is supposed to pass us a basic face id */ + } + + /* Do a quick scan through Vface_remapping_alist, and return immediately + if there is no remapping for face NAME. This is just an optimization + for the very common no-remapping case. */ + mapping = assq_no_quit (name, Vface_remapping_alist); + if (NILP (mapping)) + return face_id; /* Give up. */ + + /* If there is a remapping entry, lookup the face using NAME, which will + handle the remapping too. */ + remapped_face_id = lookup_named_face (f, name, 0); + if (remapped_face_id < 0) + return face_id; /* Give up. */ + + return remapped_face_id; +} + + /* Return the ID of the realized ASCII face of Lisp face with ID LFACE_ID on frame F. Value is -1 if LFACE_ID isn't valid. */ @@ -4758,6 +4966,7 @@ face_with_height (f, face_id, height) face = FACE_FROM_ID (f, face_id); bcopy (face->lface, attrs, sizeof attrs); attrs[LFACE_HEIGHT_INDEX] = make_number (height); + font_clear_prop (attrs, FONT_SIZE_INDEX); face_id = lookup_face (f, attrs); #endif /* HAVE_WINDOW_SYSTEM */ @@ -4786,7 +4995,9 @@ lookup_derived_face (f, symbol, face_id, signal_p) if (!default_face) abort (); - get_lface_attributes (f, symbol, symbol_attrs, signal_p); + if (!get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0)) + return -1; + bcopy (default_face->lface, attrs, sizeof attrs); merge_face_vectors (f, symbol_attrs, attrs, 0); return lookup_face (f, attrs); @@ -4870,6 +5081,7 @@ x_supports_face_attributes_p (f, attrs, def_face) /* Check font-related attributes, as those are the most commonly "unsupported" on a window-system (because of missing fonts). */ if (!UNSPECIFIEDP (attrs[LFACE_FAMILY_INDEX]) + || !UNSPECIFIEDP (attrs[LFACE_FOUNDRY_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_HEIGHT_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_WEIGHT_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_SLANT_INDEX]) @@ -4890,8 +5102,10 @@ x_supports_face_attributes_p (f, attrs, def_face) if (! face) error ("Cannot make face"); - /* If the font is the same, then not supported. */ - if (face->font == def_face->font) + /* If the font is the same, or no font is found, then not + supported. */ + if (face->font == def_face->font + || ! face->font) return 0; for (i = FONT_TYPE_INDEX; i <= FONT_SIZE_INDEX; i++) if (! EQ (face->font->props[i], def_face->font->props[i])) @@ -4955,6 +5169,7 @@ tty_supports_face_attributes_p (f, attrs, def_face) because the faked result is too different from what the face specifies. */ if (!UNSPECIFIEDP (attrs[LFACE_FAMILY_INDEX]) + || !UNSPECIFIEDP (attrs[LFACE_FOUNDRY_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_STIPPLE_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_HEIGHT_INDEX]) || !UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX]) @@ -4968,8 +5183,9 @@ tty_supports_face_attributes_p (f, attrs, def_face) /* Test for terminal `capabilities' (non-color character attributes). */ /* font weight (bold/dim) */ - weight = FONT_WEIGHT_NAME_NUMERIC (attrs[LFACE_WEIGHT_INDEX]); - if (weight >= 0) + val = attrs[LFACE_WEIGHT_INDEX]; + if (!UNSPECIFIEDP (val) + && (weight = FONT_WEIGHT_NAME_NUMERIC (val), weight >= 0)) { int def_weight = FONT_WEIGHT_NAME_NUMERIC (def_attrs[LFACE_WEIGHT_INDEX]); @@ -5182,7 +5398,7 @@ face for italic. */) Font selection ***********************************************************************/ - DEFUN ("internal-set-font-selection-order", +DEFUN ("internal-set-font-selection-order", Finternal_set_font_selection_order, Sinternal_set_font_selection_order, 1, 1, 0, doc: /* Set font selection order for face font selection to ORDER. @@ -5254,7 +5470,20 @@ be found. Value is ALIST. */) (alist) Lisp_Object alist; { + Lisp_Object entry, tail, tail2; + CHECK_LIST (alist); + alist = Fcopy_sequence (alist); + for (tail = alist; CONSP (tail); tail = XCDR (tail)) + { + entry = XCAR (tail); + CHECK_LIST (entry); + entry = Fcopy_sequence (entry); + XSETCAR (tail, entry); + for (tail2 = entry; CONSP (tail2); tail2 = XCDR (tail2)) + XSETCAR (tail2, Fintern (XCAR (tail2), Qnil)); + } + Vface_alternative_font_family_alist = alist; free_all_realized_faces (Qnil); return alist; @@ -5271,7 +5500,19 @@ be found. Value is ALIST. */) (alist) Lisp_Object alist; { + Lisp_Object entry, tail, tail2; + CHECK_LIST (alist); + alist = Fcopy_sequence (alist); + for (tail = alist; CONSP (tail); tail = XCDR (tail)) + { + entry = XCAR (tail); + CHECK_LIST (entry); + entry = Fcopy_sequence (entry); + XSETCAR (tail, entry); + for (tail2 = entry; CONSP (tail2); tail2 = XCDR (tail2)) + XSETCAR (tail2, Fdowncase (XCAR (tail2))); + } Vface_alternative_font_registry_alist = alist; free_all_realized_faces (Qnil); return alist; @@ -5394,12 +5635,15 @@ realize_default_face (f) if (!FRAME_WINDOW_P (f)) { LFACE_FAMILY (lface) = build_string ("default"); + LFACE_FOUNDRY (lface) = LFACE_FAMILY (lface); LFACE_SWIDTH (lface) = Qnormal; LFACE_HEIGHT (lface) = make_number (1); if (UNSPECIFIEDP (LFACE_WEIGHT (lface))) LFACE_WEIGHT (lface) = Qnormal; if (UNSPECIFIEDP (LFACE_SLANT (lface))) LFACE_SLANT (lface) = Qnormal; + if (UNSPECIFIEDP (LFACE_FONTSET (lface))) + LFACE_FONTSET (lface) = Qnil; } if (UNSPECIFIEDP (LFACE_UNDERLINE (lface))) @@ -5465,7 +5709,7 @@ realize_default_face (f) not support the default font. */ if (!face->font) return 0; - + /* Otherwise, the font specified for the frame was not acceptable as a font for the default face (perhaps because auto-scaled fonts are rejected), so we must adjust the frame @@ -5495,7 +5739,7 @@ realize_named_face (f, symbol, id) struct face *new_face; /* The default face must exist and be fully specified. */ - get_lface_attributes (f, Qdefault, attrs, 1); + get_lface_attributes_no_remap (f, Qdefault, attrs, 1); check_lface_attrs (attrs); xassert (lface_fully_specified_p (attrs)); @@ -5508,7 +5752,7 @@ realize_named_face (f, symbol, id) } /* Merge SYMBOL's face with the default face. */ - get_lface_attributes (f, symbol, symbol_attrs, 1); + get_lface_attributes_no_remap (f, symbol, symbol_attrs, 1); merge_face_vectors (f, symbol_attrs, attrs, 0); /* Realize the face. */ @@ -5628,7 +5872,8 @@ realize_x_face (cache, attrs) && lface_same_font_attributes_p (default_face->lface, attrs)) { face->font = default_face->font; - face->fontset = make_fontset_for_ascii_face (f, -1, face); + face->fontset + = make_fontset_for_ascii_face (f, default_face->fontset, face); } else { @@ -5645,9 +5890,12 @@ realize_x_face (cache, attrs) realizing the default face, thus the default face should have already been realized. */ if (fontset == -1) - fontset = default_face->fontset; - if (fontset == -1) - abort (); + { + if (default_face) + fontset = default_face->fontset; + if (fontset == -1) + abort (); + } if (! FONT_OBJECT_P (attrs[LFACE_FONT_INDEX])) attrs[LFACE_FONT_INDEX] = font_load_for_lface (f, attrs, attrs[LFACE_FONT_INDEX]); @@ -6012,17 +6260,21 @@ compute_char_face (f, ch, prop) If MOUSE is non-zero, use the character's mouse-face, not its face. + BASE_FACE_ID, if non-negative, specifies a base face id to use + instead of DEFAULT_FACE_ID. + The face returned is suitable for displaying ASCII characters. */ int face_at_buffer_position (w, pos, region_beg, region_end, - endptr, limit, mouse) + endptr, limit, mouse, base_face_id) struct window *w; EMACS_INT pos; EMACS_INT region_beg, region_end; EMACS_INT *endptr; EMACS_INT limit; int mouse; + int base_face_id; { struct frame *f = XFRAME (w->frame); Lisp_Object attrs[LFACE_VECTOR_SIZE]; @@ -6065,13 +6317,15 @@ face_at_buffer_position (w, pos, region_beg, region_end, *endptr = endpos; - default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID); + default_face = FACE_FROM_ID (f, base_face_id >= 0 ? base_face_id + : NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID + : lookup_basic_face (f, DEFAULT_FACE_ID)); /* Optimize common cases where we can use the default face. */ if (noverlays == 0 && NILP (prop) && !(pos >= region_beg && pos < region_end)) - return DEFAULT_FACE_ID; + return default_face->id; /* Begin with attributes from the default face. */ bcopy (default_face->lface, attrs, sizeof attrs); @@ -6320,10 +6574,10 @@ merge_faces (f, face_name, face_id, base_face_id) 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, base_face_id, 1); - if (face_id >= 0) - return face_id; - return base_face_id; + /* When called during make-frame, lookup_derived_face may fail + if the faces are uninitialized. Don't signal an error. */ + face_id = lookup_derived_face (f, face_name, base_face_id, 0); + return (face_id >= 0 ? face_id : base_face_id); } /* Begin with attributes from the base face. */ @@ -6350,6 +6604,60 @@ merge_faces (f, face_name, face_id, base_face_id) return lookup_face (f, attrs); } + + +#ifndef HAVE_X_WINDOWS +DEFUN ("x-load-color-file", Fx_load_color_file, + Sx_load_color_file, 1, 1, 0, + doc: /* Create an alist of color entries from an external file. + +The file should define one named RGB color per line like so: + R G B name +where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) + (filename) + Lisp_Object filename; +{ + FILE *fp; + Lisp_Object cmap = Qnil; + Lisp_Object abspath; + + CHECK_STRING (filename); + abspath = Fexpand_file_name (filename, Qnil); + + fp = fopen (SDATA (filename), "rt"); + if (fp) + { + char buf[512]; + int red, green, blue; + int num; + + BLOCK_INPUT; + + while (fgets (buf, sizeof (buf), fp) != NULL) { + if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3) + { + char *name = buf + num; + num = strlen (name) - 1; + if (num >= 0 && name[num] == '\n') + name[num] = 0; + cmap = Fcons (Fcons (build_string (name), +#ifdef WINDOWSNT + make_number (RGB (red, green, blue))), +#else + make_number ((red << 16) | (green << 8) | blue)), +#endif + cmap); + } + } + fclose (fp); + + UNBLOCK_INPUT; + } + + return cmap; +} +#endif + /*********************************************************************** Tests @@ -6443,152 +6751,152 @@ DEFUN ("show-face-resources", Fshow_face_resources, Sshow_face_resources, void syms_of_xfaces () { - Qface = intern ("face"); + Qface = intern_c_string ("face"); staticpro (&Qface); - Qface_no_inherit = intern ("face-no-inherit"); + Qface_no_inherit = intern_c_string ("face-no-inherit"); staticpro (&Qface_no_inherit); - Qbitmap_spec_p = intern ("bitmap-spec-p"); + Qbitmap_spec_p = intern_c_string ("bitmap-spec-p"); staticpro (&Qbitmap_spec_p); - Qframe_set_background_mode = intern ("frame-set-background-mode"); + Qframe_set_background_mode = intern_c_string ("frame-set-background-mode"); staticpro (&Qframe_set_background_mode); /* Lisp face attribute keywords. */ - QCfamily = intern (":family"); + QCfamily = intern_c_string (":family"); staticpro (&QCfamily); - QCheight = intern (":height"); + QCheight = intern_c_string (":height"); staticpro (&QCheight); - QCweight = intern (":weight"); + QCweight = intern_c_string (":weight"); staticpro (&QCweight); - QCslant = intern (":slant"); + QCslant = intern_c_string (":slant"); staticpro (&QCslant); - QCunderline = intern (":underline"); + QCunderline = intern_c_string (":underline"); staticpro (&QCunderline); - QCinverse_video = intern (":inverse-video"); + QCinverse_video = intern_c_string (":inverse-video"); staticpro (&QCinverse_video); - QCreverse_video = intern (":reverse-video"); + QCreverse_video = intern_c_string (":reverse-video"); staticpro (&QCreverse_video); - QCforeground = intern (":foreground"); + QCforeground = intern_c_string (":foreground"); staticpro (&QCforeground); - QCbackground = intern (":background"); + QCbackground = intern_c_string (":background"); staticpro (&QCbackground); - QCstipple = intern (":stipple"); + QCstipple = intern_c_string (":stipple"); staticpro (&QCstipple); - QCwidth = intern (":width"); + QCwidth = intern_c_string (":width"); staticpro (&QCwidth); - QCfont = intern (":font"); + QCfont = intern_c_string (":font"); staticpro (&QCfont); - QCfontset = intern (":fontset"); + QCfontset = intern_c_string (":fontset"); staticpro (&QCfontset); - QCbold = intern (":bold"); + QCbold = intern_c_string (":bold"); staticpro (&QCbold); - QCitalic = intern (":italic"); + QCitalic = intern_c_string (":italic"); staticpro (&QCitalic); - QCoverline = intern (":overline"); + QCoverline = intern_c_string (":overline"); staticpro (&QCoverline); - QCstrike_through = intern (":strike-through"); + QCstrike_through = intern_c_string (":strike-through"); staticpro (&QCstrike_through); - QCbox = intern (":box"); + QCbox = intern_c_string (":box"); staticpro (&QCbox); - QCinherit = intern (":inherit"); + QCinherit = intern_c_string (":inherit"); staticpro (&QCinherit); /* Symbols used for Lisp face attribute values. */ - QCcolor = intern (":color"); + QCcolor = intern_c_string (":color"); staticpro (&QCcolor); - QCline_width = intern (":line-width"); + QCline_width = intern_c_string (":line-width"); staticpro (&QCline_width); - QCstyle = intern (":style"); + QCstyle = intern_c_string (":style"); staticpro (&QCstyle); - Qreleased_button = intern ("released-button"); + Qreleased_button = intern_c_string ("released-button"); staticpro (&Qreleased_button); - Qpressed_button = intern ("pressed-button"); + Qpressed_button = intern_c_string ("pressed-button"); staticpro (&Qpressed_button); - Qnormal = intern ("normal"); + Qnormal = intern_c_string ("normal"); staticpro (&Qnormal); - Qultra_light = intern ("ultra-light"); + Qultra_light = intern_c_string ("ultra-light"); staticpro (&Qultra_light); - Qextra_light = intern ("extra-light"); + Qextra_light = intern_c_string ("extra-light"); staticpro (&Qextra_light); - Qlight = intern ("light"); + Qlight = intern_c_string ("light"); staticpro (&Qlight); - Qsemi_light = intern ("semi-light"); + Qsemi_light = intern_c_string ("semi-light"); staticpro (&Qsemi_light); - Qsemi_bold = intern ("semi-bold"); + Qsemi_bold = intern_c_string ("semi-bold"); staticpro (&Qsemi_bold); - Qbold = intern ("bold"); + Qbold = intern_c_string ("bold"); staticpro (&Qbold); - Qextra_bold = intern ("extra-bold"); + Qextra_bold = intern_c_string ("extra-bold"); staticpro (&Qextra_bold); - Qultra_bold = intern ("ultra-bold"); + Qultra_bold = intern_c_string ("ultra-bold"); staticpro (&Qultra_bold); - Qoblique = intern ("oblique"); + Qoblique = intern_c_string ("oblique"); staticpro (&Qoblique); - Qitalic = intern ("italic"); + Qitalic = intern_c_string ("italic"); staticpro (&Qitalic); - Qreverse_oblique = intern ("reverse-oblique"); + Qreverse_oblique = intern_c_string ("reverse-oblique"); staticpro (&Qreverse_oblique); - Qreverse_italic = intern ("reverse-italic"); + Qreverse_italic = intern_c_string ("reverse-italic"); staticpro (&Qreverse_italic); - Qultra_condensed = intern ("ultra-condensed"); + Qultra_condensed = intern_c_string ("ultra-condensed"); staticpro (&Qultra_condensed); - Qextra_condensed = intern ("extra-condensed"); + Qextra_condensed = intern_c_string ("extra-condensed"); staticpro (&Qextra_condensed); - Qcondensed = intern ("condensed"); + Qcondensed = intern_c_string ("condensed"); staticpro (&Qcondensed); - Qsemi_condensed = intern ("semi-condensed"); + Qsemi_condensed = intern_c_string ("semi-condensed"); staticpro (&Qsemi_condensed); - Qsemi_expanded = intern ("semi-expanded"); + Qsemi_expanded = intern_c_string ("semi-expanded"); staticpro (&Qsemi_expanded); - Qexpanded = intern ("expanded"); + Qexpanded = intern_c_string ("expanded"); staticpro (&Qexpanded); - Qextra_expanded = intern ("extra-expanded"); + Qextra_expanded = intern_c_string ("extra-expanded"); staticpro (&Qextra_expanded); - Qultra_expanded = intern ("ultra-expanded"); + Qultra_expanded = intern_c_string ("ultra-expanded"); staticpro (&Qultra_expanded); - Qbackground_color = intern ("background-color"); + Qbackground_color = intern_c_string ("background-color"); staticpro (&Qbackground_color); - Qforeground_color = intern ("foreground-color"); + Qforeground_color = intern_c_string ("foreground-color"); staticpro (&Qforeground_color); - Qunspecified = intern ("unspecified"); + Qunspecified = intern_c_string ("unspecified"); staticpro (&Qunspecified); - Qignore_defface = intern (":ignore-defface"); + Qignore_defface = intern_c_string (":ignore-defface"); staticpro (&Qignore_defface); - Qface_alias = intern ("face-alias"); + Qface_alias = intern_c_string ("face-alias"); staticpro (&Qface_alias); - Qdefault = intern ("default"); + Qdefault = intern_c_string ("default"); staticpro (&Qdefault); - Qtool_bar = intern ("tool-bar"); + Qtool_bar = intern_c_string ("tool-bar"); staticpro (&Qtool_bar); - Qregion = intern ("region"); + Qregion = intern_c_string ("region"); staticpro (&Qregion); - Qfringe = intern ("fringe"); + Qfringe = intern_c_string ("fringe"); staticpro (&Qfringe); - Qheader_line = intern ("header-line"); + Qheader_line = intern_c_string ("header-line"); staticpro (&Qheader_line); - Qscroll_bar = intern ("scroll-bar"); + Qscroll_bar = intern_c_string ("scroll-bar"); staticpro (&Qscroll_bar); - Qmenu = intern ("menu"); + Qmenu = intern_c_string ("menu"); staticpro (&Qmenu); - Qcursor = intern ("cursor"); + Qcursor = intern_c_string ("cursor"); staticpro (&Qcursor); - Qborder = intern ("border"); + Qborder = intern_c_string ("border"); staticpro (&Qborder); - Qmouse = intern ("mouse"); + Qmouse = intern_c_string ("mouse"); staticpro (&Qmouse); - Qmode_line_inactive = intern ("mode-line-inactive"); + Qmode_line_inactive = intern_c_string ("mode-line-inactive"); staticpro (&Qmode_line_inactive); - Qvertical_border = intern ("vertical-border"); + Qvertical_border = intern_c_string ("vertical-border"); staticpro (&Qvertical_border); - Qtty_color_desc = intern ("tty-color-desc"); + Qtty_color_desc = intern_c_string ("tty-color-desc"); staticpro (&Qtty_color_desc); - Qtty_color_standard_values = intern ("tty-color-standard-values"); + Qtty_color_standard_values = intern_c_string ("tty-color-standard-values"); staticpro (&Qtty_color_standard_values); - Qtty_color_by_index = intern ("tty-color-by-index"); + Qtty_color_by_index = intern_c_string ("tty-color-by-index"); staticpro (&Qtty_color_by_index); - Qtty_color_alist = intern ("tty-color-alist"); + Qtty_color_alist = intern_c_string ("tty-color-alist"); staticpro (&Qtty_color_alist); - Qscalable_fonts_allowed = intern ("scalable-fonts-allowed"); + Qscalable_fonts_allowed = intern_c_string ("scalable-fonts-allowed"); staticpro (&Qscalable_fonts_allowed); Vparam_value_alist = Fcons (Fcons (Qnil, Qnil), Qnil); @@ -6606,6 +6914,9 @@ syms_of_xfaces () #endif defsubr (&Scolor_gray_p); defsubr (&Scolor_supported_p); +#ifndef HAVE_X_WINDOWS + defsubr (&Sx_load_color_file); +#endif defsubr (&Sface_attribute_relative_p); defsubr (&Smerge_face_attribute); defsubr (&Sinternal_get_lisp_face_attribute); @@ -6648,7 +6959,7 @@ that number of fonts when searching for a matching font. */); This stipple pattern is used on monochrome displays instead of shades of gray for a face background color. See `set-face-stipple' for possible values for this variable. */); - Vface_default_stipple = build_string ("gray3"); + Vface_default_stipple = make_pure_c_string ("gray3"); DEFVAR_LISP ("tty-defined-color-alist", &Vtty_defined_color_alist, doc: /* An alist of defined terminal colors and their RGB values. */); @@ -6670,10 +6981,47 @@ Each element is a regular expression that matches names of fonts to ignore. */); Vface_ignored_fonts = Qnil; + DEFVAR_LISP ("face-remapping-alist", &Vface_remapping_alist, + doc: /* Alist of face remappings. +Each element is of the form: + + (FACE REPLACEMENT...), + +which causes display of the face FACE to use REPLACEMENT... instead. +REPLACEMENT... is interpreted the same way the value of a `face' text +property is: it may be (1) A face name, (2) A list of face names, (3) A +property-list of face attribute/value pairs, or (4) A list of face names +intermixed with lists containing face attribute/value pairs. + +Multiple entries in REPLACEMENT... are merged together to form the final +result, with faces or attributes earlier in the list taking precedence +over those that are later. + +Face-name remapping cycles are suppressed; recursive references use the +underlying face instead of the remapped face. So a remapping of the form: + + (FACE EXTRA-FACE... FACE) + +or: + + (FACE (FACE-ATTR VAL ...) FACE) + +will cause EXTRA-FACE... or (FACE-ATTR VAL ...) to be _merged_ with the +existing definition of FACE. Note that for the default face, this isn't +necessary, as every face inherits from the default face. + +Making this variable buffer-local is a good way to allow buffer-specific +face definitions. For instance, the mode my-mode could define a face +`my-mode-default', and then in the mode setup function, do: + + (set (make-local-variable 'face-remapping-alist) + '((default my-mode-default)))). */); + Vface_remapping_alist = Qnil; + DEFVAR_LISP ("face-font-rescale-alist", &Vface_font_rescale_alist, doc: /* Alist of fonts vs the rescaling factors. -Each element is a cons (FONT-NAME-PATTERN . RESCALE-RATIO), where -FONT-NAME-PATTERN is a regular expression matching a font name, and +Each element is a cons (FONT-PATTERN . RESCALE-RATIO), where +FONT-PATTERN is a font-spec or a regular expression matching a font name, and RESCALE-RATIO is a floating point number to specify how much larger \(or smaller) font we should use. For instance, if a face requests a font of 10 point, we actually use a font of 10 * RESCALE-RATIO point. */); @@ -6684,8 +7032,7 @@ a font of 10 point, we actually use a font of 10 * RESCALE-RATIO point. */); defsubr (&Sx_list_fonts); defsubr (&Sinternal_face_x_get_resource); defsubr (&Sx_family_fonts); - defsubr (&Sx_font_family_list); -#endif /* HAVE_WINDOW_SYSTEM */ +#endif } /* arch-tag: 8a0f7598-5517-408d-9ab3-1da6fcd4c749