X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/357f32fcd0e00337a3c1359a4919e716ed81fe52..0b75e9a4194f34ff1c579c2dabf99424029b540c:/src/xfaces.c diff --git a/src/xfaces.c b/src/xfaces.c index 643c8de18a..50a80b6f91 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1,5 +1,5 @@ -/* "Face" primitives - Copyright (C) 1992, 1993 Free Software Foundation. +/* "Face" primitives. + Copyright (C) 1993, 1994 Free Software Foundation. This file is part of GNU Emacs. @@ -15,69 +15,176 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* This is derived from work by Lucid (some parts very loosely so). */ #include #include -#include "config.h" +#include #include "lisp.h" +#ifdef HAVE_FACES + +#ifdef HAVE_X_WINDOWS #include "xterm.h" +#endif +#ifdef MSDOS +#include "dosfns.h" +#endif #include "buffer.h" #include "dispextern.h" #include "frame.h" #include "blockinput.h" -/* #include "window.h" */ +#include "window.h" +#include "intervals.h" -/* Display Context for the icons */ -#include -#include -#include +#ifdef HAVE_X_WINDOWS +/* Compensate for bug in Xos.h on some systems, on which it requires + time.h. On some such systems, Xos.h tries to redefine struct + timeval and struct timezone if USG is #defined while it is + #included. */ +#ifdef XOS_NEEDS_TIME_H + +#include +#undef USG #include +#define USG +#define __TIMEVAL__ -/* We use face structures in two ways: - At the frame level, each frame has a vector of faces (FRAME_FACES). - Face number 0 is the default face (for normal text). - Face number 1 is the mode line face. - Higher face numbers have no built-in meaning. - The faces in these vectors are called "frame faces". - - Faces number 0 and 1 have graphics contexts. - They can be used in the redisplay code directly. - Higher numbered frame faces do not have graphics contexts. +#else - There are also "cached faces". They have graphics contexts. - They are kept in a C vector called face_vector. +#include - A "display face" is a face with a graphics context. - It is either a frame face number 0 or 1, - or a cached face. */ +#endif +#endif /* HAVE_X_WINDOWS */ + +/* An explanation of the face data structures. */ + +/* ========================= Face Data Structures ========================= + + Let FACE-NAME be a symbol naming a face. + + Let FACE-VECTOR be (assq FACE-NAME (frame-face-alist FRAME)) + FACE-VECTOR is either nil, or a vector of the form + [face NAME ID FONT FOREGROUND BACKGROUND BACKGROUND-PIXMAP UNDERLINE-P] + where + face is the symbol `face', + NAME is the symbol with which this vector is associated (a backpointer), + ID is the face ID, an integer used internally by the C code to identify + the face, + FONT, FOREGROUND, and BACKGROUND are strings naming the fonts and colors + to use with the face, + BACKGROUND-PIXMAP is the name of an x bitmap filename, which we don't + use right now, and + UNDERLINE-P is non-nil if the face should be underlined. + If any of these elements are nil, that parameter is considered + unspecified; parameters from faces specified by lower-priority + overlays or text properties, or the parameters of the frame itself, + can show through. (lisp/faces.el maintains these lists.) + + (assq FACE-NAME global-face-data) returns a vector describing the + global parameters for that face. + + Let PARAM-FACE be FRAME->output_data.x->param_faces[Faref (FACE-VECTOR, 2)]. + PARAM_FACE is a struct face whose members are the Xlib analogues of + the parameters in FACE-VECTOR. If an element of FACE-VECTOR is + nil, then the corresponding member of PARAM_FACE is FACE_DEFAULT. + These faces are called "parameter faces", because they're the ones + lisp manipulates to control what gets displayed. Elements 0 and 1 + of FRAME->output_data.x->param_faces are special - they describe the + default and mode line faces. None of the faces in param_faces have + GC's. (See src/dispextern.h for the definition of struct face. + lisp/faces.el maintains the isomorphism between face_alist and + param_faces.) + + The functions compute_char_face and compute_glyph_face find and + combine the parameter faces associated with overlays and text + properties. The resulting faces are called "computed faces"; none + of their members are FACE_DEFAULT; they are completely specified. + They then call intern_compute_face to search + FRAME->output_data.x->computed_faces for a matching face, add one if + none is found, and return the index into + FRAME->output_data.x->computed_faces. FRAME's glyph matrices use these + indices to record the faces of the matrix characters, and the X + display hooks consult compute_faces to decide how to display these + characters. Elements 0 and 1 of computed_faces always describe the + default and mode-line faces. + + Each computed face belongs to a particular frame. + + Computed faces have graphics contexts some of the time. + intern_face builds a GC for a specified computed face + if it doesn't have one already. + clear_face_cache clears out the GCs of all computed faces. + This is done from time to time so that we don't hold on to + lots of GCs that are no longer needed. + + If a computed face has 0 as its font, + it is unused, and can be reused by new_computed_face. + + Constraints: + + Symbols naming faces must have associations on all frames; for any + FRAME, for all FACE-NAME, if (assq FACE-NAME (frame-face-alist + FRAME)) is non-nil, it must be non-nil for all frames. + + Analogously, indices into param_faces must be valid on all frames; + if param_faces[i] is a non-zero face pointer on one frame, then it + must be filled in on all frames. Code assumes that face ID's can + be used on any frame. + + Some subtleties: -/* A table of display faces. */ -struct face **face_vector; -/* The length in use of the table. */ -int nfaces; -/* The allocated length of the table. */ -int nfaces_allocated; + Why do we keep param_faces and computed_faces separate? + computed_faces contains an element for every combination of facial + parameters we have ever displayed. indices into param_faces have + to be valid on all frames. If they were the same array, then that + array would grow very large on all frames, because any facial + combination displayed on any frame would need to be a valid entry + on all frames. */ + +/* Definitions and declarations. */ /* The number of face-id's in use (same for all frames). */ -int next_face_id; +static int next_face_id; + +/* The number of the face to use to indicate the region. */ +static int region_face; +/* This is what appears in a slot in a face to signify that the face + does not specify that display aspect. */ #define FACE_DEFAULT (~0) -Lisp_Object Qface, Qwindow, Qpriority; +Lisp_Object Qface, Qmouse_face; +Lisp_Object Qpixmap_spec_p; -static struct face *allocate_face (); -static void build_face (); -static int sort_overlays (); -static struct face *get_display_face (); -static Lisp_Object face_name_id_number (); +int face_name_id_number ( /* FRAME_PTR, Lisp_Object name */ ); + +struct face *intern_face ( /* FRAME_PTR, struct face * */ ); +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 */ ); -/* Make a new face that's a copy of an existing one. */ +/* Allocating, copying, and comparing struct faces. */ +/* Allocate a new face */ +static struct face * +allocate_face () +{ + struct face *result = (struct face *) xmalloc (sizeof (struct face)); + bzero (result, sizeof (struct face)); + result->font = (XFontStruct *) FACE_DEFAULT; + result->foreground = FACE_DEFAULT; + result->background = FACE_DEFAULT; + result->stipple = FACE_DEFAULT; + return result; +} + +/* Make a new face that's a copy of an existing one. */ static struct face * copy_face (face) struct face *face; @@ -89,6 +196,8 @@ copy_face (face) result->background = face->background; result->stipple = face->stipple; result->underline = face->underline; + result->pixmap_h = face->pixmap_h; + result->pixmap_w = face->pixmap_w; return result; } @@ -97,532 +206,886 @@ static int face_eql (face1, face2) struct face *face1, *face2; { - return (face1->font == face2->font + return ( face1->font == face2->font && face1->foreground == face2->foreground && face1->background == face2->background - && face1->stipple == face2->stipple - && face1->underline == face2->underline); + && face1->stipple == face2->stipple + && face1->underline == face2->underline); } + +/* Managing graphics contexts of faces. */ -/* Return the unique display face corresponding to the user-level face FACE. - - If there isn't one, make one, and find a slot in the face_vector to - put it in. */ +#ifdef HAVE_X_WINDOWS +/* Given a computed face, construct its graphics context if necessary. */ -static struct face * -get_cached_face (f, face) +struct face * +intern_face (f, face) struct frame *f; struct face *face; { - int i, empty = -1; - struct face *result; + GC gc; + XGCValues xgcv; + unsigned long mask; - /* Look for an existing display face that does the job. - Also find an empty slot if any. */ - for (i = 0; i < nfaces; i++) - { - if (face_eql (face_vector[i], face)) - return face_vector[i]; - if (face_vector[i] == 0) - empty = i; - } + if (face->gc) + return face; - /* If no empty slots, make one. */ - if (empty < 0 && nfaces == nfaces_allocated) + BLOCK_INPUT; + + if (face->foreground != FACE_DEFAULT) + xgcv.foreground = face->foreground; + else + xgcv.foreground = f->output_data.x->foreground_pixel; + + if (face->background != FACE_DEFAULT) + xgcv.background = face->background; + else + xgcv.background = f->output_data.x->background_pixel; + + if (face->font && face->font != (XFontStruct *) FACE_DEFAULT) + xgcv.font = face->font->fid; + else + xgcv.font = f->output_data.x->font->fid; + + xgcv.graphics_exposures = 0; + + mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; + if (face->stipple && face->stipple != FACE_DEFAULT) { - int newsize = nfaces + 20; - face_vector - = (struct face **) xrealloc (face_vector, - newsize * sizeof (struct face *)); - nfaces_allocated = newsize; + xgcv.fill_style = FillStippled; + xgcv.stipple = x_bitmap_pixmap (f, face->stipple); + mask |= GCFillStyle | GCStipple; } - if (empty < 0) - empty = nfaces++; + gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + mask, &xgcv); + + face->gc = gc; - /* Put a new display face in the empty slot. */ - result = copy_face (face); - face_vector[empty] = result; - - /* Make a graphics context for it. */ - build_face (f, result); + UNBLOCK_INPUT; - return result; + return face; } -/* Clear out face_vector and start anew. +/* Clear out all graphics contexts for all computed faces + except for the default and mode line faces. This should be done from time to time just to avoid - keeping too many graphics contexts in face_vector - that are no longer needed. */ + keeping too many graphics contexts that are no longer needed. */ void -clear_face_vector () +clear_face_cache () { - Lisp_Object rest; - Display *dpy = x_current_display; - int i; + Lisp_Object tail, frame; BLOCK_INPUT; - /* Free the display faces in the face_vector. */ - for (i = 0; i < nfaces; i++) + FOR_EACH_FRAME (tail, frame) { - struct face *face = face_vector[i]; - if (face->gc) - XFreeGC (dpy, face->gc); - xfree (face); + FRAME_PTR f = XFRAME (frame); + if (FRAME_X_P (f)) + { + int i; + Display *dpy = FRAME_X_DISPLAY (f); + + for (i = 2; i < FRAME_N_COMPUTED_FACES (f); i++) + { + struct face *face = FRAME_COMPUTED_FACES (f) [i]; + if (face->gc) + XFreeGC (dpy, face->gc); + face->gc = 0; + } + } } - nfaces = 0; UNBLOCK_INPUT; } -/* Make a graphics context for face FACE, which is on frame F, - if that can be done. */ +/* Allocating, freeing, and duplicating fonts, colors, and pixmaps. -static void -build_face (f, face) - struct frame* f; - struct face* face; + These functions operate on param faces only. + Computed faces get their fonts, colors and pixmaps + by merging param faces. */ + +static XFontStruct * +load_font (f, name) + struct frame *f; + Lisp_Object name; { - GC gc; - XGCValues xgcv; - unsigned long mask; + XFontStruct *font; - if (face->foreground != FACE_DEFAULT) - xgcv.foreground = face->foreground; - else - xgcv. foreground = f->display.x->foreground_pixel; - if (face->background != FACE_DEFAULT) - xgcv.background = face->background; - else - xgcv. background = f->display.x->background_pixel; - if (face->font && (int) face->font != FACE_DEFAULT) - xgcv.font = face->font->fid; - else - xgcv.font = f->display.x->font->fid; - xgcv.graphics_exposures = 0; - mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; - gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f), - mask, &xgcv); -#if 0 - if (face->stipple && face->stipple != FACE_DEFAULT) - XSetStipple (x_current_display, gc, face->stipple); -#endif - face->gc = gc; + if (NILP (name)) + return (XFontStruct *) FACE_DEFAULT; + + CHECK_STRING (name, 0); + BLOCK_INPUT; + font = XLoadQueryFont (FRAME_X_DISPLAY (f), (char *) XSTRING (name)->data); + UNBLOCK_INPUT; + + if (! font) + Fsignal (Qerror, Fcons (build_string ("undefined font"), + Fcons (name, Qnil))); + return font; } - -/* Modify face TO by copying from FROM all properties which have - nondefault settings. */ -static void -merge_faces (from, to) - struct face *from, *to; +static void +unload_font (f, font) + struct frame *f; + XFontStruct *font; { - if (from->font != (XFontStruct *)FACE_DEFAULT) + int len = FRAME_N_COMPUTED_FACES (f); + int i; + + if (!font || font == ((XFontStruct *) FACE_DEFAULT)) + return; + + BLOCK_INPUT; + /* Invalidate any computed faces which use this font, + and free their GC's if they have any. */ + for (i = 2; i < len; i++) { - to->font = from->font; + struct face *face = FRAME_COMPUTED_FACES (f)[i]; + if (face->font == font) + { + Display *dpy = FRAME_X_DISPLAY (f); + if (face->gc) + XFreeGC (dpy, face->gc); + face->gc = 0; + /* This marks the computed face as available to reuse. */ + face->font = 0; + } } - if (from->foreground != FACE_DEFAULT) - to->foreground = from->foreground; - if (from->background != FACE_DEFAULT) - to->background = from->background; - if (from->stipple != FACE_DEFAULT) - to->stipple = from->stipple; - if (from->underline) - to->underline = from->underline; + + XFreeFont (FRAME_X_DISPLAY (f), font); + UNBLOCK_INPUT; } -struct sortvec +static unsigned long +load_color (f, name) + struct frame *f; + Lisp_Object name; { - Lisp_Object overlay; - int beg, end; - int priority; -}; + XColor color; + int result; -/* Return the display face associated with a buffer position POS. - Store into *ENDPTR the position at which a different face is needed. - This does not take account of glyphs that specify their own face codes. - F is the frame in use for display, and W is the window. */ + if (NILP (name)) + return FACE_DEFAULT; -struct face * -compute_char_face (f, w, pos, endptr) + 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); + if (! result) + Fsignal (Qerror, Fcons (build_string ("undefined color"), + Fcons (name, Qnil))); + return (unsigned long) color.pixel; +} + +static void +unload_color (f, pixel) struct frame *f; - struct window *w; - int pos; - int *endptr; + unsigned long pixel; { - struct face face; - Lisp_Object prop, position, length; - Lisp_Object overlay, start, end; - int i, j, noverlays; - int facecode; - int endpos; - Lisp_Object *overlay_vec; - int len; - struct sortvec *sortvec; - Lisp_Object frame; + Colormap cmap; + Display *dpy = FRAME_X_DISPLAY (f); + int class = FRAME_X_DISPLAY_INFO (f)->visual->class; - XSET (frame, Lisp_Frame, f); + if (pixel == FACE_DEFAULT + || pixel == BLACK_PIX_DEFAULT (f) + || pixel == WHITE_PIX_DEFAULT (f)) + return; + cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)); + + /* If display has an immutable color map, freeing colors is not + necessary and some servers don't allow it. So don't do it. */ + if (! (class == StaticColor || class == StaticGray || class == TrueColor)) + { + int len = FRAME_N_COMPUTED_FACES (f); + int i; - XFASTINT (position) = pos; - prop = Fget_text_property (position, Qface); + BLOCK_INPUT; + /* Invalidate any computed faces which use this color, + and free their GC's if they have any. */ + for (i = 2; i < len; i++) + { + struct face *face = FRAME_COMPUTED_FACES (f)[i]; + if (face->foreground == pixel + || face->background == pixel) + { + Display *dpy = FRAME_X_DISPLAY (f); + if (face->gc) + XFreeGC (dpy, face->gc); + face->gc = 0; + /* This marks the computed face as available to reuse. */ + face->font = 0; + } + } - len = 10; - overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, &overlay_vec, &len, &endpos); + XFreeColors (dpy, cmap, &pixel, 1, (unsigned long)0); + UNBLOCK_INPUT; + } +} - /* Optimize the default case. */ - if (noverlays == 0 && NILP (prop)) - return FRAME_DEFAULT_FACE (f); +DEFUN ("pixmap-spec-p", Fpixmap_spec_p, Spixmap_spec_p, 1, 1, 0, + "Return t if OBJECT is a valid pixmap specification.") + (object) + Lisp_Object object; +{ + Lisp_Object height, width; + + return ((STRINGP (object) + || (CONSP (object) + && CONSP (XCONS (object)->cdr) + && CONSP (XCONS (XCONS (object)->cdr)->cdr) + && NILP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->cdr) + && (width = XCONS (object)->car, INTEGERP (width)) + && (height = XCONS (XCONS (object)->cdr)->car, INTEGERP (height)) + && STRINGP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car) + && XINT (width) > 0 + && XINT (height) > 0 + /* The string must have enough bits for width * height. */ + && ((XSTRING (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)->size + * (BITS_PER_INT / sizeof (int))) + >= XFASTINT (width) * XFASTINT (height)))) + ? Qt : Qnil); +} - bcopy (FRAME_DEFAULT_FACE (f), &face, sizeof (struct face)); +/* Load a bitmap according to NAME (which is either a file name + or a pixmap spec). Return the bitmap_id (see xfns.c) + or get an error if NAME is invalid. - if (!NILP (prop)) - { - facecode = face_name_id_number (frame, prop); - if (facecode >= 0 && facecode < FRAME_N_FACES (f) - && FRAME_FACES (f) [facecode] != 0) - merge_faces (FRAME_FACES (f) [facecode], &face); - } + Store the bitmap width in *W_PTR and height in *H_PTR. */ - /* Put the valid and relevant overlays into sortvec. */ - sortvec = (struct sortvec *) alloca (noverlays * sizeof (struct sortvec)); +static long +load_pixmap (f, name, w_ptr, h_ptr) + FRAME_PTR f; + Lisp_Object name; + unsigned int *w_ptr, *h_ptr; +{ + int bitmap_id; + Lisp_Object tem; - for (i = 0, j = 0; i < noverlays; i++) + if (NILP (name)) + return FACE_DEFAULT; + + tem = Fpixmap_spec_p (name); + if (NILP (tem)) + wrong_type_argument (Qpixmap_spec_p, name); + + BLOCK_INPUT; + + if (CONSP (name)) { - overlay = overlay_vec[i]; + /* Decode a bitmap spec into a bitmap. */ - if (OVERLAY_VALID (overlay) - && OVERLAY_POSITION (OVERLAY_START (overlay)) > 0 - && OVERLAY_POSITION (OVERLAY_END (overlay)) > 0) - { - Lisp_Object window; - window = Foverlay_get (overlay, Qwindow); + int h, w; + Lisp_Object bits; - /* Also ignore overlays limited to one window - if it's not the window we are using. */ - if (NILP (window) || XWINDOW (window) == w) - { - Lisp_Object tem; - - /* This overlay is good and counts: - put it in sortvec. */ - sortvec[j].overlay = overlay; - sortvec[j].beg = OVERLAY_POSITION (OVERLAY_START (overlay)); - sortvec[j].end = OVERLAY_POSITION (OVERLAY_END (overlay)); - tem = Foverlay_get (overlay, Qpriority); - if (INTEGERP (tem)) - sortvec[j].priority = XINT (tem); - else - sortvec[j].priority = 0; - j++; - } - } + w = XINT (Fcar (name)); + h = XINT (Fcar (Fcdr (name))); + bits = Fcar (Fcdr (Fcdr (name))); + + bitmap_id = x_create_bitmap_from_data (f, XSTRING (bits)->data, + w, h); } - noverlays = j; + else + { + /* It must be a string -- a file name. */ + bitmap_id = x_create_bitmap_from_file (f, name); + } + UNBLOCK_INPUT; - /* Sort the overlays into the proper order: increasing priority. */ + if (bitmap_id < 0) + Fsignal (Qerror, Fcons (build_string ("invalid or undefined bitmap"), + Fcons (name, Qnil))); - qsort (sortvec, noverlays, sizeof (struct sortvec), sort_overlays); + *w_ptr = x_bitmap_width (f, bitmap_id); + *h_ptr = x_bitmap_height (f, bitmap_id); - /* Now merge the overlay data in that order. */ + return bitmap_id; +} - for (i = 0; i < noverlays; i++) - { - prop = Foverlay_get (overlay_vec[i], Qface); - if (!NILP (prop)) - { - Lisp_Object oend; - int oendpos; +#else /* !HAVE_X_WINDOWS */ - facecode = face_name_id_number (frame, prop); - if (facecode >= 0 && facecode < FRAME_N_FACES (f) - && FRAME_FACES (f) [facecode] != 0) - merge_faces (FRAME_FACES (f) [facecode], &face); +/* Stubs for MSDOS when not under X. */ - oend = OVERLAY_END (overlay_vec[i]); - oendpos = OVERLAY_POSITION (oend); - if (oendpos > endpos) - endpos = oendpos; - } - } +struct face * +intern_face (f, face) + struct frame *f; + struct face *face; +{ + return face; +} + +void +clear_face_cache () +{ + /* No action. */ +} - xfree (overlay_vec); +#ifdef MSDOS +unsigned long +load_color (f, name) + FRAME_PTR f; + Lisp_Object name; +{ + Lisp_Object result; - *endptr = endpos; + if (NILP (name)) + return FACE_DEFAULT; - return get_display_face (f, &face); + CHECK_STRING (name, 0); + result = call1 (Qmsdos_color_translate, name); + if (INTEGERP (result)) + return XINT (result); + else + Fsignal (Qerror, Fcons (build_string ("undefined color"), + Fcons (name, Qnil))); } +#endif +#endif /* !HAVE_X_WINDOWS */ -int -sort_overlays (s1, s2) - struct sortvec *s1, *s2; + +/* Managing parameter face arrays for frames. */ + +void +init_frame_faces (f) + FRAME_PTR f; { - if (s1->priority != s2->priority) - return s1->priority - s2->priority; - if (s1->beg != s2->beg) - return s1->beg - s2->beg; - if (s1->end != s2->end) - return s2->end - s1->end; - return 0; + ensure_face_ready (f, 0); + ensure_face_ready (f, 1); + + FRAME_N_COMPUTED_FACES (f) = 0; + FRAME_SIZE_COMPUTED_FACES (f) = 0; + + new_computed_face (f, FRAME_PARAM_FACES (f)[0]); + 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; + + result = Qnil; + FOR_EACH_FRAME (tail, frame) + if ((FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame))) + && XFRAME (frame) != f) + { + result = frame; + break; + } + + /* If we didn't find any X frames other than f, then we don't need + any faces other than 0 and 1, so we're okay. Otherwise, make + sure that all faces valid on the selected frame are also valid + on this new frame. */ + if (FRAMEP (result)) + { + int i; + int n_faces = FRAME_N_PARAM_FACES (XFRAME (result)); + struct face **faces = FRAME_PARAM_FACES (XFRAME (result)); + + for (i = 2; i < n_faces; i++) + if (faces[i]) + ensure_face_ready (f, i); + } + } +#endif /* MULTI_FRAME */ } -/* Return the display face to use to display a special glyph - which selects FACE_CODE as the face ID, - assuming that ordinarily the face would be BASIC_FACE. - F is the frame. */ -struct face * -compute_glyph_face (f, basic_face, face_code) +/* Called from Fdelete_frame. */ + +void +free_frame_faces (f) struct frame *f; - struct face *basic_face; - int face_code; { - struct face face; + Display *dpy = FRAME_X_DISPLAY (f); + int i; - bcopy (basic_face, &face, sizeof (struct face)); + BLOCK_INPUT; - if (face_code >= 0 && face_code < FRAME_N_FACES (f) - && FRAME_FACES (f) [face_code] != 0) - merge_faces (FRAME_FACES (f) [face_code], &face); + for (i = 0; i < FRAME_N_PARAM_FACES (f); i++) + { + struct face *face = FRAME_PARAM_FACES (f) [i]; + if (face) + { + unload_font (f, face->font); + unload_color (f, face->foreground); + unload_color (f, face->background); + x_destroy_bitmap (f, face->stipple); + xfree (face); + } + } + xfree (FRAME_PARAM_FACES (f)); + FRAME_PARAM_FACES (f) = 0; + FRAME_N_PARAM_FACES (f) = 0; + + /* All faces in FRAME_COMPUTED_FACES use resources copied from + FRAME_PARAM_FACES; we can free them without fuss. + But we do free the GCs and the face objects themselves. */ + for (i = 0; i < FRAME_N_COMPUTED_FACES (f); i++) + { + struct face *face = FRAME_COMPUTED_FACES (f) [i]; + if (face) + { + if (face->gc) + XFreeGC (dpy, face->gc); + xfree (face); + } + } + xfree (FRAME_COMPUTED_FACES (f)); + FRAME_COMPUTED_FACES (f) = 0; + FRAME_N_COMPUTED_FACES (f) = 0; - return get_display_face (f, &face); + UNBLOCK_INPUT; } -/* Given a frame face, return an equivalent display face - (one which has a graphics context). */ +/* Interning faces in a frame's face array. */ -static struct face * -get_display_face (f, face) +static int +new_computed_face (f, new_face) struct frame *f; - struct face *face; + struct face *new_face; { - struct face *result; + int len = FRAME_N_COMPUTED_FACES (f); + int i; - /* Does the face have a GC already? */ - if (face->gc) - return face; - - /* If it's equivalent to the default face, use that. */ - if (face->font == FRAME_DEFAULT_FACE (f)->font - && face->foreground == FRAME_DEFAULT_FACE (f)->foreground - && face->background == FRAME_DEFAULT_FACE (f)->background - && face->stipple == FRAME_DEFAULT_FACE (f)->stipple - && face->underline == FRAME_DEFAULT_FACE (f)->underline) + /* Search for an unused computed face in the middle of the table. */ + for (i = 0; i < len; i++) { - if (!FRAME_DEFAULT_FACE (f)->gc) - build_face (f, FRAME_DEFAULT_FACE (f)); - return FRAME_DEFAULT_FACE (f); + struct face *face = FRAME_COMPUTED_FACES (f)[i]; + if (face->font == 0) + { + FRAME_COMPUTED_FACES (f)[i] = copy_face (new_face); + return i; + } } - /* If it's equivalent to the mode line face, use that. */ - if (face->font == FRAME_MODE_LINE_FACE (f)->font - && face->foreground == FRAME_MODE_LINE_FACE (f)->foreground - && face->background == FRAME_MODE_LINE_FACE (f)->background - && face->stipple == FRAME_MODE_LINE_FACE (f)->stipple - && face->underline == FRAME_MODE_LINE_FACE (f)->underline) + if (i >= FRAME_SIZE_COMPUTED_FACES (f)) { - if (!FRAME_MODE_LINE_FACE (f)->gc) - build_face (f, FRAME_MODE_LINE_FACE (f)); - return FRAME_MODE_LINE_FACE (f); + int new_size = i + 32; + + FRAME_COMPUTED_FACES (f) + = (struct face **) (FRAME_SIZE_COMPUTED_FACES (f) == 0 + ? xmalloc (new_size * sizeof (struct face *)) + : xrealloc (FRAME_COMPUTED_FACES (f), + new_size * sizeof (struct face *))); + FRAME_SIZE_COMPUTED_FACES (f) = new_size; } - /* Get a specialized display face. */ - return get_cached_face (f, face); + i = FRAME_N_COMPUTED_FACES (f)++; + FRAME_COMPUTED_FACES (f)[i] = copy_face (new_face); + return i; } - -/* Allocate a new face */ -static struct face * -allocate_face () + +/* Find a match for NEW_FACE in a FRAME's computed face array, and add + it if we don't find one. */ +static int +intern_computed_face (f, new_face) + struct frame *f; + struct face *new_face; { - struct face *result = (struct face *) xmalloc (sizeof (struct face)); - bzero (result, sizeof (struct face)); - result->font = (XFontStruct *) FACE_DEFAULT; - result->foreground = FACE_DEFAULT; - result->background = FACE_DEFAULT; - result->stipple = FACE_DEFAULT; - return result; + int len = FRAME_N_COMPUTED_FACES (f); + int i; + + /* Search for a computed face already on F equivalent to FACE. */ + for (i = 0; i < len; i++) + { + if (! FRAME_COMPUTED_FACES (f)[i]) + abort (); + if (face_eql (new_face, FRAME_COMPUTED_FACES (f)[i])) + return i; + } + + /* We didn't find one; add a new one. */ + return new_computed_face (f, new_face); } -/* Make face id ID valid on frame F. */ +/* Make parameter face id ID valid on frame F. */ -void +static void ensure_face_ready (f, id) struct frame *f; int id; { - if (FRAME_N_FACES (f) <= id) + if (FRAME_N_PARAM_FACES (f) <= id) { int n = id + 10; int i; - if (!FRAME_N_FACES (f)) - FRAME_FACES (f) + if (!FRAME_N_PARAM_FACES (f)) + FRAME_PARAM_FACES (f) = (struct face **) xmalloc (sizeof (struct face *) * n); else - FRAME_FACES (f) - = (struct face **) xrealloc (FRAME_FACES (f), + FRAME_PARAM_FACES (f) + = (struct face **) xrealloc (FRAME_PARAM_FACES (f), sizeof (struct face *) * n); - bzero (FRAME_FACES (f) + FRAME_N_FACES (f), - (n - FRAME_N_FACES (f)) * sizeof (struct face *)); - FRAME_N_FACES (f) = n; + bzero (FRAME_PARAM_FACES (f) + FRAME_N_PARAM_FACES (f), + (n - FRAME_N_PARAM_FACES (f)) * sizeof (struct face *)); + FRAME_N_PARAM_FACES (f) = n; } - if (FRAME_FACES (f) [id] == 0) - FRAME_FACES (f) [id] = allocate_face (); + if (FRAME_PARAM_FACES (f) [id] == 0) + FRAME_PARAM_FACES (f) [id] = allocate_face (); } -/* Allocating, freeing, and duplicating fonts, colors, and pixmaps. */ - #ifdef HAVE_X_WINDOWS +/* Return non-zero if FONT1 and FONT2 have the same width. + We do not check the height, because we can now deal with + different heights. + We assume that they're both character-cell fonts. */ -static XFontStruct * -load_font (f, name) - struct frame *f; - Lisp_Object name; +int +same_size_fonts (font1, font2) + XFontStruct *font1, *font2; { - XFontStruct *font; + XCharStruct *bounds1 = &font1->min_bounds; + XCharStruct *bounds2 = &font2->min_bounds; - if (NILP (name)) - return (XFontStruct *) FACE_DEFAULT; + return (bounds1->width == bounds2->width); +} - CHECK_STRING (name, 0); - BLOCK_INPUT; - font = XLoadQueryFont (x_current_display, (char *) XSTRING (name)->data); - UNBLOCK_INPUT; +/* Update the line_height of frame F according to the biggest font in + any face. Return nonzero if if line_height changes. */ - if (! font) - Fsignal (Qerror, Fcons (build_string ("undefined font"), - Fcons (name, Qnil))); - return font; +int +frame_update_line_height (f) + FRAME_PTR f; +{ + int i; + int biggest = 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); + if (height > biggest) + biggest = height; + } + + if (biggest == f->output_data.x->line_height) + return 0; + + f->output_data.x->line_height = biggest; + return 1; } +#endif /* not HAVE_X_WINDOWS */ + +/* Modify face TO by copying from FROM all properties which have + nondefault settings. */ + +static void +merge_faces (from, to) + struct face *from, *to; +{ + /* Only merge the font if it's the same width as the base font. + Otherwise ignore it, since we can't handle it properly. */ + if (from->font != (XFontStruct *) FACE_DEFAULT + && same_size_fonts (from->font, to->font)) + to->font = from->font; + if (from->foreground != FACE_DEFAULT) + to->foreground = from->foreground; + if (from->background != FACE_DEFAULT) + to->background = from->background; + if (from->stipple != FACE_DEFAULT) + { + to->stipple = from->stipple; + to->pixmap_h = from->pixmap_h; + to->pixmap_w = from->pixmap_w; + } + if (from->underline) + to->underline = from->underline; +} + +/* Set up the basic set of facial parameters, based on the frame's + data; all faces are deltas applied to this. */ static void -unload_font (f, font) - struct frame *f; - XFontStruct *font; +compute_base_face (f, face) + FRAME_PTR f; + struct face *face; { - if (!font || font == ((XFontStruct *) FACE_DEFAULT)) - return; - XFreeFont (x_current_display, font); + face->gc = 0; + face->foreground = FRAME_FOREGROUND_PIXEL (f); + face->background = FRAME_BACKGROUND_PIXEL (f); + face->font = FRAME_FONT (f); + face->stipple = 0; + face->underline = 0; } -static unsigned long -load_color (f, name) +/* Return the face ID to use to display a special glyph which selects + FACE_CODE as the face ID, assuming that ordinarily the face would + be CURRENT_FACE. F is the frame. */ + +int +compute_glyph_face (f, face_code, current_face) struct frame *f; - Lisp_Object name; + int face_code, current_face; { - Display *dpy = x_current_display; - Colormap cmap; - XColor color; - int result; + struct face face; - if (NILP (name)) - return FACE_DEFAULT; + face = *FRAME_COMPUTED_FACES (f)[current_face]; - cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display)); + if (face_code >= 0 && face_code < FRAME_N_PARAM_FACES (f) + && FRAME_PARAM_FACES (f) [face_code] != 0) + merge_faces (FRAME_PARAM_FACES (f) [face_code], &face); - CHECK_STRING (name, 0); - BLOCK_INPUT; - result = XParseColor (dpy, cmap, (char *) XSTRING (name)->data, &color); - UNBLOCK_INPUT; - if (! result) - Fsignal (Qerror, Fcons (build_string ("undefined color"), - Fcons (name, Qnil))); - BLOCK_INPUT; - result = XAllocColor (dpy, cmap, &color); - UNBLOCK_INPUT; - if (! result) - Fsignal (Qerror, Fcons (build_string ("X server cannot allocate color"), - Fcons (name, Qnil))); - return (unsigned long) color.pixel; + return intern_computed_face (f, &face); } -static void -unload_color (f, pixel) +/* Return the face ID to use to display a special glyph which selects + FACE_CODE as the face ID, assuming that ordinarily the face would + be CURRENT_FACE. F is the frame. */ + +int +compute_glyph_face_1 (f, face_name, current_face) struct frame *f; - Pixel pixel; + Lisp_Object face_name; + int current_face; { - Colormap cmap; - Display *dpy = x_current_display; - if (pixel == FACE_DEFAULT) - return; - cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display)); - BLOCK_INPUT; - XFreeColors (dpy, cmap, &pixel, 1, 0); - UNBLOCK_INPUT; -} + struct face face; -#endif /* HAVE_X_WINDOWS */ + face = *FRAME_COMPUTED_FACES (f)[current_face]; + if (!NILP (face_name)) + { + int facecode = face_name_id_number (f, face_name); + if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f) + && FRAME_PARAM_FACES (f) [facecode] != 0) + merge_faces (FRAME_PARAM_FACES (f) [facecode], &face); + } + + return intern_computed_face (f, &face); +} -/* frames */ +/* Return the face ID associated with a buffer position POS. + Store into *ENDPTR the position at which a different face is needed. + This does not take account of glyphs that specify their own face codes. + F is the frame in use for display, and W is a window displaying + the current buffer. -void -init_frame_faces (f) + REGION_BEG, REGION_END delimit the region, so it can be highlighted. + + LIMIT is a position not to scan beyond. That is to limit + the time this function can take. + + If MOUSE is nonzero, use the character's mouse-face, not its face. */ + +int +compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse) struct frame *f; + struct window *w; + int pos; + int region_beg, region_end; + int *endptr; + int limit; + int mouse; { - struct frame *other_frame = 0; - Lisp_Object rest; + struct face face; + Lisp_Object prop, position; + int i, j, noverlays; + int facecode; + Lisp_Object *overlay_vec; + Lisp_Object frame; + int endpos; + Lisp_Object propname; + + /* W must display the current buffer. We could write this function + to use the frame and buffer of W, but right now it doesn't. */ + if (XBUFFER (w->buffer) != current_buffer) + abort (); + + XSETFRAME (frame, f); + + endpos = ZV; + if (pos < region_beg && region_beg < endpos) + endpos = region_beg; + + XSETFASTINT (position, pos); + + if (mouse) + propname = Qmouse_face; + else + propname = Qface; + + prop = Fget_text_property (position, propname, w->buffer); + + { + Lisp_Object limit1, end; + + XSETFASTINT (limit1, (limit < endpos ? limit : endpos)); + end = Fnext_single_property_change (position, propname, w->buffer, limit1); + if (INTEGERP (end)) + endpos = XINT (end); + } + + { + int next_overlay; + int len; + + /* First try with room for 40 overlays. */ + len = 40; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + + noverlays = overlays_at (pos, 0, &overlay_vec, &len, + &next_overlay, (int *) 0); + + /* If there are more than 40, + make enough space for all, and try again. */ + if (noverlays > len) + { + len = noverlays; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, + &next_overlay, (int *) 0); + } + + if (next_overlay < endpos) + endpos = next_overlay; + } + + *endptr = endpos; - for (rest = Vframe_list; !NILP (rest); rest = Fcdr (rest)) + /* Optimize the default case. */ + if (noverlays == 0 && NILP (prop) + && !(pos >= region_beg && pos < region_end)) + return 0; + + compute_base_face (f, &face); + + if (CONSP (prop)) { - struct frame *f2 = XFRAME (Fcar (rest)); - if (f2 != f && FRAME_X_P (f2)) + /* 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++) { - other_frame = f2; - break; + 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); } } + else if (!NILP (prop)) + { + 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); + } + + noverlays = sort_overlays (overlay_vec, noverlays, w); - if (other_frame) + /* Now merge the overlay data in that order. */ + for (i = 0; i < noverlays; i++) { - /* Make sure this frame's face vector is as big as the others. */ - FRAME_N_FACES (f) = FRAME_N_FACES (other_frame); - FRAME_FACES (f) - = (struct face **) xmalloc (FRAME_N_FACES (f) * sizeof (struct face *)); - - /* Make sure the frame has the two basic faces. */ - FRAME_DEFAULT_FACE (f) - = copy_face (FRAME_DEFAULT_FACE (other_frame)); - FRAME_MODE_LINE_FACE (f) - = copy_face (FRAME_MODE_LINE_FACE (other_frame)); + prop = Foverlay_get (overlay_vec[i], propname); + if (CONSP (prop)) + { + /* 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); + } + } + else if (!NILP (prop)) + { + Lisp_Object oend; + int oendpos; + + 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); + + 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); + } -/* Called from Fdelete_frame? */ + *endptr = endpos; + + return intern_computed_face (f, &face); +} + +/* Recompute the GC's for the default and modeline faces. + We call this after changing frame parameters on which those GC's + depend. */ void -free_screen_faces (f) - struct frame *f; +recompute_basic_faces (f) + FRAME_PTR f; { - Display *dpy = x_current_display; - int i; + /* If the frame's faces haven't been initialized yet, don't worry about + this stuff. */ + if (FRAME_N_PARAM_FACES (f) < 2) + return; - for (i = 0; i < FRAME_N_FACES (f); i++) - { - struct face *face = FRAME_FACES (f) [i]; - if (! face) - continue; - if (face->gc) - XFreeGC (dpy, face->gc); - unload_font (f, face->font); - unload_color (f, face->foreground); - unload_color (f, face->background); -#if 0 - unload_pixmap (f, face->stipple); -#endif - xfree (face); - } - xfree (FRAME_FACES (f)); - FRAME_FACES (f) = 0; - FRAME_N_FACES (f) = 0; + BLOCK_INPUT; + + if (FRAME_DEFAULT_FACE (f)->gc) + XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->gc); + if (FRAME_MODE_LINE_FACE (f)->gc) + XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->gc); + + compute_base_face (f, FRAME_DEFAULT_FACE (f)); + compute_base_face (f, FRAME_MODE_LINE_FACE (f)); + + merge_faces (FRAME_DEFAULT_PARAM_FACE (f), FRAME_DEFAULT_FACE (f)); + merge_faces (FRAME_MODE_LINE_PARAM_FACE (f), FRAME_MODE_LINE_FACE (f)); + + intern_face (f, FRAME_DEFAULT_FACE (f)); + intern_face (f, FRAME_MODE_LINE_FACE (f)); + + UNBLOCK_INPUT; } + -/* Lisp interface */ +/* Lisp interface. */ DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0, "") @@ -649,17 +1112,17 @@ DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0, (face_id) Lisp_Object face_id; { - Lisp_Object rest; + Lisp_Object rest, frame; int id = XINT (face_id); CHECK_NUMBER (face_id, 0); if (id < 0 || id >= next_face_id) error ("Face id out of range"); - for (rest = Vframe_list; !NILP (rest); rest = XCONS (rest)->cdr) + FOR_EACH_FRAME (rest, frame) { - struct frame *f = XFRAME (XCONS (rest)->car); - ensure_face_ready (f, id); + if (FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame))) + ensure_face_ready (XFRAME (frame), id); } return Qnil; } @@ -674,6 +1137,7 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal, struct frame *f; int magic_p; int id; + int garbaged = 0; CHECK_FRAME (frame, 0); CHECK_NUMBER (face_id, 0); @@ -684,41 +1148,54 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal, if (id < 0 || id >= next_face_id) error ("Face id out of range"); + if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f)) + return Qnil; + ensure_face_ready (f, id); - face = FRAME_FACES (f) [XFASTINT (face_id)]; + face = FRAME_PARAM_FACES (f) [XFASTINT (face_id)]; if (EQ (attr_name, intern ("font"))) { +#if defined (MSDOS) && !defined (HAVE_X_WINDOWS) + /* The one and only font. Must *not* be zero (which + is taken to mean an unused face nowadays). */ + face->font = (XFontStruct *)1 ; +#else XFontStruct *font = load_font (f, attr_value); - unload_font (f, face->font); + if (face->font != f->output_data.x->font) + unload_font (f, face->font); face->font = font; + 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 + we just got rid of. */ + garbaged = 1; +#endif } else if (EQ (attr_name, intern ("foreground"))) { unsigned long new_color = load_color (f, attr_value); unload_color (f, face->foreground); face->foreground = new_color; + garbaged = 1; } else if (EQ (attr_name, intern ("background"))) { unsigned long new_color = load_color (f, attr_value); unload_color (f, face->background); face->background = new_color; + garbaged = 1; } -#if 0 else if (EQ (attr_name, intern ("background-pixmap"))) { - unsigned int w, h, d; - unsigned long new_pixmap = load_pixmap (f, attr_value, &w, &h, &d, 0); - unload_pixmap (f, face->stipple); - if (NILP (attr_value)) - new_pixmap = 0; + unsigned int w, h; + unsigned long new_pixmap = load_pixmap (f, attr_value, &w, &h); + x_destroy_bitmap (f, face->stipple); face->stipple = new_pixmap; face->pixmap_w = w; face->pixmap_h = h; -/* face->pixmap_depth = d; */ + garbaged = 1; } -#endif /* 0 */ else if (EQ (attr_name, intern ("underline"))) { int new = !NILP (attr_value); @@ -727,23 +1204,16 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal, else error ("unknown face attribute"); - if (id == 0) - { - BLOCK_INPUT; - if (FRAME_DEFAULT_FACE (f)->gc != 0) - XFreeGC (x_current_display, FRAME_DEFAULT_FACE (f)->gc); - build_face (f, FRAME_DEFAULT_FACE (f)); - UNBLOCK_INPUT; - } + if (id == 0 || id == 1) + recompute_basic_faces (f); - if (id == 1) - { - BLOCK_INPUT; - if (FRAME_MODE_LINE_FACE (f)->gc != 0) - XFreeGC (x_current_display, FRAME_MODE_LINE_FACE (f)->gc); - build_face (f, FRAME_MODE_LINE_FACE (f)); - UNBLOCK_INPUT; - } + /* We must redraw the frame whenever any face font or color changes, + because it's possible that a merged (display) face + contains the font or color we just replaced. + And we must inhibit any Expose events until the redraw is done, + since they would try to use the invalid display faces. */ + if (garbaged) + SET_FRAME_GARBAGED (f); return Qnil; } @@ -760,33 +1230,47 @@ DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id, but it's as easy to use the "right" frame to look it up as to use any other one.) */ -static Lisp_Object -face_name_id_number (frame, name) - Lisp_Object frame, name; +int +face_name_id_number (f, name) + FRAME_PTR f; + Lisp_Object name; { Lisp_Object tem; - CHECK_FRAME (frame, 0); - tem = Fcdr (Fassq (name, XFRAME (frame)->face_alist)); + tem = Fcdr (assq_no_quit (name, f->face_alist)); + if (NILP (tem)) + return 0; CHECK_VECTOR (tem, 0); tem = XVECTOR (tem)->contents[2]; CHECK_NUMBER (tem, 0); return XINT (tem); } +/* Emacs initialization. */ + void syms_of_xfaces () { - Qwindow = intern ("window"); - staticpro (&Qwindow); Qface = intern ("face"); staticpro (&Qface); - Qpriority = intern ("priority"); - staticpro (&Qpriority); + Qmouse_face = intern ("mouse-face"); + staticpro (&Qmouse_face); + Qpixmap_spec_p = intern ("pixmap-spec-p"); + staticpro (&Qpixmap_spec_p); + + DEFVAR_INT ("region-face", ®ion_face, + "Face number to use to highlight the region\n\ +The region is highlighted with this face\n\ +when Transient Mark mode is enabled and the mark is active."); +#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 */