Delete all menu-enable properties.
[bpt/emacs.git] / src / xfaces.c
CommitLineData
cb637678 1/* "Face" primitives.
3a22ee35 2 Copyright (C) 1993, 1994 Free Software Foundation.
7b7739b1 3
c115973b
JB
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7b7739b1 8the Free Software Foundation; either version 2, or (at your option)
c115973b
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
c115973b 20
357f32fc 21/* This is derived from work by Lucid (some parts very loosely so). */
7b7739b1 22
c115973b
JB
23#include <sys/types.h>
24#include <sys/stat.h>
25
18160b98 26#include <config.h>
c115973b
JB
27#include "lisp.h"
28
a8517066
KH
29#include "charset.h"
30
87485d6f 31#ifdef HAVE_FACES
cb637678 32
87485d6f 33#ifdef HAVE_X_WINDOWS
c115973b 34#include "xterm.h"
a8517066 35#include "fontset.h"
87485d6f
MW
36#endif
37#ifdef MSDOS
38#include "dosfns.h"
39#endif
c115973b 40#include "buffer.h"
f211082d 41#include "dispextern.h"
7b7739b1 42#include "frame.h"
357f32fc 43#include "blockinput.h"
b6d40e46 44#include "window.h"
bde7c500 45#include "intervals.h"
c115973b 46
87485d6f 47#ifdef HAVE_X_WINDOWS
657070ac
JB
48/* Compensate for bug in Xos.h on some systems, on which it requires
49 time.h. On some such systems, Xos.h tries to redefine struct
50 timeval and struct timezone if USG is #defined while it is
51 #included. */
6233db35 52#ifdef XOS_NEEDS_TIME_H
657070ac 53
e11d186d 54#include <time.h>
657070ac
JB
55#undef USG
56#include <X11/Xos.h>
57#define USG
e11d186d 58#define __TIMEVAL__
e11d186d 59
657070ac 60#else
7a4d2269 61
c115973b
JB
62#include <X11/Xos.h>
63
657070ac 64#endif
87485d6f 65#endif /* HAVE_X_WINDOWS */
cb637678
JB
66\f
67/* An explanation of the face data structures. */
68
69/* ========================= Face Data Structures =========================
70
7b00de84 71 Let FACE-NAME be a symbol naming a face.
cb637678 72
7b00de84
JB
73 Let FACE-VECTOR be (assq FACE-NAME (frame-face-alist FRAME))
74 FACE-VECTOR is either nil, or a vector of the form
cb637678
JB
75 [face NAME ID FONT FOREGROUND BACKGROUND BACKGROUND-PIXMAP UNDERLINE-P]
76 where
77 face is the symbol `face',
78 NAME is the symbol with which this vector is associated (a backpointer),
79 ID is the face ID, an integer used internally by the C code to identify
80 the face,
81 FONT, FOREGROUND, and BACKGROUND are strings naming the fonts and colors
a8517066 82 to use with the face, FONT may name fontsets,
cb637678
JB
83 BACKGROUND-PIXMAP is the name of an x bitmap filename, which we don't
84 use right now, and
85 UNDERLINE-P is non-nil if the face should be underlined.
7b00de84
JB
86 If any of these elements are nil, that parameter is considered
87 unspecified; parameters from faces specified by lower-priority
88 overlays or text properties, or the parameters of the frame itself,
89 can show through. (lisp/faces.el maintains these lists.)
90
91 (assq FACE-NAME global-face-data) returns a vector describing the
92 global parameters for that face.
93
7556890b 94 Let PARAM-FACE be FRAME->output_data.x->param_faces[Faref (FACE-VECTOR, 2)].
7b00de84
JB
95 PARAM_FACE is a struct face whose members are the Xlib analogues of
96 the parameters in FACE-VECTOR. If an element of FACE-VECTOR is
97 nil, then the corresponding member of PARAM_FACE is FACE_DEFAULT.
98 These faces are called "parameter faces", because they're the ones
99 lisp manipulates to control what gets displayed. Elements 0 and 1
7556890b 100 of FRAME->output_data.x->param_faces are special - they describe the
7b00de84 101 default and mode line faces. None of the faces in param_faces have
8e6208c5 102 GC's. (See src/dispextern.h for the definition of struct face.
7b00de84
JB
103 lisp/faces.el maintains the isomorphism between face_alist and
104 param_faces.)
105
106 The functions compute_char_face and compute_glyph_face find and
107 combine the parameter faces associated with overlays and text
108 properties. The resulting faces are called "computed faces"; none
109 of their members are FACE_DEFAULT; they are completely specified.
110 They then call intern_compute_face to search
7556890b 111 FRAME->output_data.x->computed_faces for a matching face, add one if
7b00de84 112 none is found, and return the index into
7556890b 113 FRAME->output_data.x->computed_faces. FRAME's glyph matrices use these
7b00de84
JB
114 indices to record the faces of the matrix characters, and the X
115 display hooks consult compute_faces to decide how to display these
116 characters. Elements 0 and 1 of computed_faces always describe the
117 default and mode-line faces.
118
cd0bb842
RS
119 Each computed face belongs to a particular frame.
120
42120bc7
RS
121 Computed faces have graphics contexts some of the time.
122 intern_face builds a GC for a specified computed face
123 if it doesn't have one already.
124 clear_face_cache clears out the GCs of all computed faces.
125 This is done from time to time so that we don't hold on to
126 lots of GCs that are no longer needed.
7b00de84 127
195f798e
RS
128 If a computed face has 0 as its font,
129 it is unused, and can be reused by new_computed_face.
130
7b00de84
JB
131 Constraints:
132
133 Symbols naming faces must have associations on all frames; for any
134 FRAME, for all FACE-NAME, if (assq FACE-NAME (frame-face-alist
135 FRAME)) is non-nil, it must be non-nil for all frames.
136
137 Analogously, indices into param_faces must be valid on all frames;
138 if param_faces[i] is a non-zero face pointer on one frame, then it
139 must be filled in on all frames. Code assumes that face ID's can
140 be used on any frame.
cb637678
JB
141
142 Some subtleties:
7b7739b1 143
7b00de84
JB
144 Why do we keep param_faces and computed_faces separate?
145 computed_faces contains an element for every combination of facial
146 parameters we have ever displayed. indices into param_faces have
147 to be valid on all frames. If they were the same array, then that
148 array would grow very large on all frames, because any facial
149 combination displayed on any frame would need to be a valid entry
42120bc7 150 on all frames. */
cb637678
JB
151\f
152/* Definitions and declarations. */
153
c115973b 154/* The number of face-id's in use (same for all frames). */
f8758da5 155static int next_face_id;
c115973b 156
bc0db68d 157/* The number of the face to use to indicate the region. */
f8758da5 158static int region_face;
bc0db68d 159
9516fe94
RS
160/* This is what appears in a slot in a face to signify that the face
161 does not specify that display aspect. */
7b7739b1
JB
162#define FACE_DEFAULT (~0)
163
6f134486 164Lisp_Object Qface, Qmouse_face;
cd0bb842 165Lisp_Object Qpixmap_spec_p;
f211082d 166
415445e2 167int face_name_id_number ( /* FRAME_PTR, Lisp_Object name */ );
cb637678 168
415445e2 169struct face *intern_face ( /* FRAME_PTR, struct face * */ );
7b00de84
JB
170static int new_computed_face ( /* FRAME_PTR, struct face * */ );
171static int intern_computed_face ( /* FRAME_PTR, struct face * */ );
415445e2 172static void ensure_face_ready ( /* FRAME_PTR, int id */ );
254a1b66 173void recompute_basic_faces ( /* FRAME_PTR f */ );
c115973b 174\f
cb637678
JB
175/* Allocating, copying, and comparing struct faces. */
176
177/* Allocate a new face */
178static struct face *
179allocate_face ()
180{
181 struct face *result = (struct face *) xmalloc (sizeof (struct face));
182 bzero (result, sizeof (struct face));
183 result->font = (XFontStruct *) FACE_DEFAULT;
a8517066 184 result->fontset = -1;
cb637678
JB
185 result->foreground = FACE_DEFAULT;
186 result->background = FACE_DEFAULT;
187 result->stipple = FACE_DEFAULT;
188 return result;
189}
c115973b 190
cb637678 191/* Make a new face that's a copy of an existing one. */
c115973b
JB
192static struct face *
193copy_face (face)
194 struct face *face;
195{
196 struct face *result = allocate_face ();
197
198 result->font = face->font;
a8517066 199 result->fontset = face->fontset;
c115973b
JB
200 result->foreground = face->foreground;
201 result->background = face->background;
f211082d 202 result->stipple = face->stipple;
c115973b 203 result->underline = face->underline;
cd0bb842
RS
204 result->pixmap_h = face->pixmap_h;
205 result->pixmap_w = face->pixmap_w;
c115973b
JB
206
207 return result;
208}
209
210static int
211face_eql (face1, face2)
212 struct face *face1, *face2;
213{
cb637678 214 return ( face1->font == face2->font
a8517066 215 && face1->fontset == face2->fontset
c115973b
JB
216 && face1->foreground == face2->foreground
217 && face1->background == face2->background
cb637678
JB
218 && face1->stipple == face2->stipple
219 && face1->underline == face2->underline);
c115973b 220}
cb637678 221\f
42120bc7 222/* Managing graphics contexts of faces. */
c115973b 223
87485d6f 224#ifdef HAVE_X_WINDOWS
42120bc7 225/* Given a computed face, construct its graphics context if necessary. */
cb637678
JB
226
227struct face *
228intern_face (f, face)
229 struct frame *f;
230 struct face *face;
c115973b
JB
231{
232 GC gc;
233 XGCValues xgcv;
234 unsigned long mask;
235
42120bc7
RS
236 if (face->gc)
237 return face;
238
660ed669
JB
239 BLOCK_INPUT;
240
f211082d
JB
241 if (face->foreground != FACE_DEFAULT)
242 xgcv.foreground = face->foreground;
243 else
7556890b 244 xgcv.foreground = f->output_data.x->foreground_pixel;
660ed669 245
f211082d
JB
246 if (face->background != FACE_DEFAULT)
247 xgcv.background = face->background;
248 else
7556890b 249 xgcv.background = f->output_data.x->background_pixel;
660ed669 250
3f000d8c 251 if (face->font && face->font != (XFontStruct *) FACE_DEFAULT)
f211082d
JB
252 xgcv.font = face->font->fid;
253 else
7556890b 254 xgcv.font = f->output_data.x->font->fid;
660ed669 255
c115973b 256 xgcv.graphics_exposures = 0;
660ed669 257
c115973b 258 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
cd0bb842 259 if (face->stipple && face->stipple != FACE_DEFAULT)
95887807
RS
260 {
261 xgcv.fill_style = FillStippled;
262 xgcv.stipple = x_bitmap_pixmap (f, face->stipple);
263 mask |= GCFillStyle | GCStipple;
264 }
cd0bb842 265
42120bc7 266 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
c115973b 267 mask, &xgcv);
660ed669 268
f211082d 269 face->gc = gc;
a8517066
KH
270 /* We used the following GC for all non-ASCII characters by changing
271 only GCfont each time. */
272 face->non_ascii_gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
273 mask, &xgcv);
660ed669
JB
274
275 UNBLOCK_INPUT;
42120bc7
RS
276
277 return face;
c115973b 278}
cb637678 279
42120bc7
RS
280/* Clear out all graphics contexts for all computed faces
281 except for the default and mode line faces.
282 This should be done from time to time just to avoid
283 keeping too many graphics contexts that are no longer needed. */
284
285void
286clear_face_cache ()
287{
288 Lisp_Object tail, frame;
289
290 BLOCK_INPUT;
291 FOR_EACH_FRAME (tail, frame)
292 {
293 FRAME_PTR f = XFRAME (frame);
294 if (FRAME_X_P (f))
295 {
296 int i;
297 Display *dpy = FRAME_X_DISPLAY (f);
298
299 for (i = 2; i < FRAME_N_COMPUTED_FACES (f); i++)
300 {
301 struct face *face = FRAME_COMPUTED_FACES (f) [i];
302 if (face->gc)
a8517066
KH
303 {
304 XFreeGC (dpy, face->gc);
305 XFreeGC (dpy, face->non_ascii_gc);
306 }
42120bc7
RS
307 face->gc = 0;
308 }
309 }
310 }
311
312 UNBLOCK_INPUT;
313}
314\f
cd0bb842
RS
315/* Allocating, freeing, and duplicating fonts, colors, and pixmaps.
316
317 These functions operate on param faces only.
318 Computed faces get their fonts, colors and pixmaps
319 by merging param faces. */
cb637678
JB
320
321static XFontStruct *
322load_font (f, name)
323 struct frame *f;
324 Lisp_Object name;
325{
326 XFontStruct *font;
327
328 if (NILP (name))
329 return (XFontStruct *) FACE_DEFAULT;
330
331 CHECK_STRING (name, 0);
332 BLOCK_INPUT;
42120bc7 333 font = XLoadQueryFont (FRAME_X_DISPLAY (f), (char *) XSTRING (name)->data);
cb637678
JB
334 UNBLOCK_INPUT;
335
336 if (! font)
337 Fsignal (Qerror, Fcons (build_string ("undefined font"),
338 Fcons (name, Qnil)));
339 return font;
340}
341
342static void
343unload_font (f, font)
344 struct frame *f;
345 XFontStruct *font;
346{
195f798e
RS
347 int len = FRAME_N_COMPUTED_FACES (f);
348 int i;
349
cb637678
JB
350 if (!font || font == ((XFontStruct *) FACE_DEFAULT))
351 return;
660ed669
JB
352
353 BLOCK_INPUT;
195f798e
RS
354 /* Invalidate any computed faces which use this font,
355 and free their GC's if they have any. */
f3400cf9 356 for (i = 2; i < len; i++)
195f798e
RS
357 {
358 struct face *face = FRAME_COMPUTED_FACES (f)[i];
359 if (face->font == font)
360 {
361 Display *dpy = FRAME_X_DISPLAY (f);
362 if (face->gc)
363 XFreeGC (dpy, face->gc);
364 face->gc = 0;
f3400cf9 365 /* This marks the computed face as available to reuse. */
195f798e
RS
366 face->font = 0;
367 }
368 }
369
42120bc7 370 XFreeFont (FRAME_X_DISPLAY (f), font);
660ed669 371 UNBLOCK_INPUT;
cb637678
JB
372}
373
374static unsigned long
375load_color (f, name)
376 struct frame *f;
377 Lisp_Object name;
378{
cb637678
JB
379 XColor color;
380 int result;
381
382 if (NILP (name))
383 return FACE_DEFAULT;
384
cb637678 385 CHECK_STRING (name, 0);
34dda5f4
KH
386 /* if the colormap is full, defined_color will return a best match
387 to the values in an an existing cell. */
a992f9d9 388 result = defined_color(f, (char *) XSTRING (name)->data, &color, 1);
cb637678
JB
389 if (! result)
390 Fsignal (Qerror, Fcons (build_string ("undefined color"),
391 Fcons (name, Qnil)));
cb637678
JB
392 return (unsigned long) color.pixel;
393}
394
395static void
396unload_color (f, pixel)
397 struct frame *f;
7a4d2269 398 unsigned long pixel;
cb637678
JB
399{
400 Colormap cmap;
42120bc7 401 Display *dpy = FRAME_X_DISPLAY (f);
828e66d1
RS
402 int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
403
32dc0866 404 if (pixel == FACE_DEFAULT
0704eec9
RS
405 || pixel == BLACK_PIX_DEFAULT (f)
406 || pixel == WHITE_PIX_DEFAULT (f))
cb637678 407 return;
42120bc7 408 cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy));
828e66d1
RS
409
410 /* If display has an immutable color map, freeing colors is not
411 necessary and some servers don't allow it. So don't do it. */
412 if (! (class == StaticColor || class == StaticGray || class == TrueColor))
413 {
195f798e
RS
414 int len = FRAME_N_COMPUTED_FACES (f);
415 int i;
416
828e66d1 417 BLOCK_INPUT;
195f798e
RS
418 /* Invalidate any computed faces which use this color,
419 and free their GC's if they have any. */
f3400cf9 420 for (i = 2; i < len; i++)
195f798e
RS
421 {
422 struct face *face = FRAME_COMPUTED_FACES (f)[i];
423 if (face->foreground == pixel
424 || face->background == pixel)
425 {
426 Display *dpy = FRAME_X_DISPLAY (f);
427 if (face->gc)
428 XFreeGC (dpy, face->gc);
429 face->gc = 0;
f3400cf9 430 /* This marks the computed face as available to reuse. */
195f798e
RS
431 face->font = 0;
432 }
433 }
434
828e66d1
RS
435 XFreeColors (dpy, cmap, &pixel, 1, (unsigned long)0);
436 UNBLOCK_INPUT;
437 }
cd0bb842
RS
438}
439
440DEFUN ("pixmap-spec-p", Fpixmap_spec_p, Spixmap_spec_p, 1, 1, 0,
ed791d5b
EN
441 "Return t if OBJECT is a valid pixmap specification.")
442 (object)
443 Lisp_Object object;
cd0bb842
RS
444{
445 Lisp_Object height, width;
446
ed791d5b
EN
447 return ((STRINGP (object)
448 || (CONSP (object)
449 && CONSP (XCONS (object)->cdr)
450 && CONSP (XCONS (XCONS (object)->cdr)->cdr)
451 && NILP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->cdr)
452 && (width = XCONS (object)->car, INTEGERP (width))
453 && (height = XCONS (XCONS (object)->cdr)->car, INTEGERP (height))
454 && STRINGP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)
cd0bb842
RS
455 && XINT (width) > 0
456 && XINT (height) > 0
457 /* The string must have enough bits for width * height. */
ed791d5b 458 && ((XSTRING (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)->size
68be917d 459 * (BITS_PER_INT / sizeof (int)))
e1befa75 460 >= XFASTINT (width) * XFASTINT (height))))
cd0bb842
RS
461 ? Qt : Qnil);
462}
463
464/* Load a bitmap according to NAME (which is either a file name
465 or a pixmap spec). Return the bitmap_id (see xfns.c)
466 or get an error if NAME is invalid.
467
468 Store the bitmap width in *W_PTR and height in *H_PTR. */
469
470static long
471load_pixmap (f, name, w_ptr, h_ptr)
7812a96f 472 FRAME_PTR f;
cd0bb842
RS
473 Lisp_Object name;
474 unsigned int *w_ptr, *h_ptr;
475{
476 int bitmap_id;
477 Lisp_Object tem;
478
479 if (NILP (name))
480 return FACE_DEFAULT;
481
482 tem = Fpixmap_spec_p (name);
483 if (NILP (tem))
484 wrong_type_argument (Qpixmap_spec_p, name);
485
486 BLOCK_INPUT;
487
488 if (CONSP (name))
489 {
490 /* Decode a bitmap spec into a bitmap. */
491
492 int h, w;
493 Lisp_Object bits;
494
495 w = XINT (Fcar (name));
496 h = XINT (Fcar (Fcdr (name)));
497 bits = Fcar (Fcdr (Fcdr (name)));
498
499 bitmap_id = x_create_bitmap_from_data (f, XSTRING (bits)->data,
500 w, h);
501 }
502 else
503 {
504 /* It must be a string -- a file name. */
505 bitmap_id = x_create_bitmap_from_file (f, name);
506 }
507 UNBLOCK_INPUT;
508
7812a96f
RS
509 if (bitmap_id < 0)
510 Fsignal (Qerror, Fcons (build_string ("invalid or undefined bitmap"),
cd0bb842
RS
511 Fcons (name, Qnil)));
512
513 *w_ptr = x_bitmap_width (f, bitmap_id);
514 *h_ptr = x_bitmap_height (f, bitmap_id);
515
516 return bitmap_id;
cb637678 517}
87485d6f
MW
518
519#else /* !HAVE_X_WINDOWS */
520
521/* Stubs for MSDOS when not under X. */
522
523struct face *
524intern_face (f, face)
525 struct frame *f;
526 struct face *face;
527{
528 return face;
529}
530
531void
532clear_face_cache ()
533{
534 /* No action. */
535}
536
87485d6f
MW
537#ifdef MSDOS
538unsigned long
539load_color (f, name)
540 FRAME_PTR f;
541 Lisp_Object name;
542{
543 Lisp_Object result;
544
545 if (NILP (name))
546 return FACE_DEFAULT;
547
548 CHECK_STRING (name, 0);
549 result = call1 (Qmsdos_color_translate, name);
550 if (INTEGERP (result))
551 return XINT (result);
552 else
553 Fsignal (Qerror, Fcons (build_string ("undefined color"),
554 Fcons (name, Qnil)));
555}
556#endif
557#endif /* !HAVE_X_WINDOWS */
558
cb637678 559\f
7b00de84 560/* Managing parameter face arrays for frames. */
cb637678 561
cb637678
JB
562void
563init_frame_faces (f)
660ed669 564 FRAME_PTR f;
cb637678
JB
565{
566 ensure_face_ready (f, 0);
cb637678 567 ensure_face_ready (f, 1);
660ed669 568
fffc2367
RS
569 FRAME_N_COMPUTED_FACES (f) = 0;
570 FRAME_SIZE_COMPUTED_FACES (f) = 0;
571
7b00de84
JB
572 new_computed_face (f, FRAME_PARAM_FACES (f)[0]);
573 new_computed_face (f, FRAME_PARAM_FACES (f)[1]);
660ed669 574 recompute_basic_faces (f);
7b37f67b 575
1120eb5e
JB
576 /* Find another X frame. */
577 {
578 Lisp_Object tail, frame, result;
579
580 result = Qnil;
581 FOR_EACH_FRAME (tail, frame)
50e3dcf5 582 if ((FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame)))
1120eb5e
JB
583 && XFRAME (frame) != f)
584 {
585 result = frame;
586 break;
587 }
588
589 /* If we didn't find any X frames other than f, then we don't need
590 any faces other than 0 and 1, so we're okay. Otherwise, make
591 sure that all faces valid on the selected frame are also valid
592 on this new frame. */
593 if (FRAMEP (result))
594 {
595 int i;
7b00de84
JB
596 int n_faces = FRAME_N_PARAM_FACES (XFRAME (result));
597 struct face **faces = FRAME_PARAM_FACES (XFRAME (result));
1120eb5e
JB
598
599 for (i = 2; i < n_faces; i++)
600 if (faces[i])
601 ensure_face_ready (f, i);
602 }
603 }
cb637678
JB
604}
605
660ed669 606
cb637678 607/* Called from Fdelete_frame. */
cd0bb842 608
cb637678
JB
609void
610free_frame_faces (f)
611 struct frame *f;
612{
42120bc7 613 Display *dpy = FRAME_X_DISPLAY (f);
cb637678
JB
614 int i;
615
660ed669
JB
616 BLOCK_INPUT;
617
7b00de84 618 for (i = 0; i < FRAME_N_PARAM_FACES (f); i++)
cb637678 619 {
7b00de84 620 struct face *face = FRAME_PARAM_FACES (f) [i];
660ed669
JB
621 if (face)
622 {
a8517066
KH
623 if (face->fontset < 0)
624 unload_font (f, face->font);
7b00de84
JB
625 unload_color (f, face->foreground);
626 unload_color (f, face->background);
cd0bb842 627 x_destroy_bitmap (f, face->stipple);
660ed669
JB
628 xfree (face);
629 }
cb637678 630 }
7b00de84
JB
631 xfree (FRAME_PARAM_FACES (f));
632 FRAME_PARAM_FACES (f) = 0;
633 FRAME_N_PARAM_FACES (f) = 0;
634
635 /* All faces in FRAME_COMPUTED_FACES use resources copied from
42120bc7
RS
636 FRAME_PARAM_FACES; we can free them without fuss.
637 But we do free the GCs and the face objects themselves. */
638 for (i = 0; i < FRAME_N_COMPUTED_FACES (f); i++)
639 {
640 struct face *face = FRAME_COMPUTED_FACES (f) [i];
641 if (face)
642 {
643 if (face->gc)
a8517066
KH
644 {
645 XFreeGC (dpy, face->gc);
646 XFreeGC (dpy, face->non_ascii_gc);
647 }
42120bc7
RS
648 xfree (face);
649 }
650 }
7b00de84
JB
651 xfree (FRAME_COMPUTED_FACES (f));
652 FRAME_COMPUTED_FACES (f) = 0;
653 FRAME_N_COMPUTED_FACES (f) = 0;
660ed669
JB
654
655 UNBLOCK_INPUT;
cb637678 656}
c115973b 657\f
cb637678
JB
658/* Interning faces in a frame's face array. */
659
660ed669 660static int
7b00de84
JB
661new_computed_face (f, new_face)
662 struct frame *f;
663 struct face *new_face;
664{
195f798e
RS
665 int len = FRAME_N_COMPUTED_FACES (f);
666 int i;
667
668 /* Search for an unused computed face in the middle of the table. */
669 for (i = 0; i < len; i++)
670 {
671 struct face *face = FRAME_COMPUTED_FACES (f)[i];
672 if (face->font == 0)
673 {
674 FRAME_COMPUTED_FACES (f)[i] = copy_face (new_face);
675 return i;
676 }
677 }
7b00de84
JB
678
679 if (i >= FRAME_SIZE_COMPUTED_FACES (f))
680 {
681 int new_size = i + 32;
682
683 FRAME_COMPUTED_FACES (f)
fffc2367
RS
684 = (struct face **) (FRAME_SIZE_COMPUTED_FACES (f) == 0
685 ? xmalloc (new_size * sizeof (struct face *))
686 : xrealloc (FRAME_COMPUTED_FACES (f),
687 new_size * sizeof (struct face *)));
7b00de84
JB
688 FRAME_SIZE_COMPUTED_FACES (f) = new_size;
689 }
690
691 i = FRAME_N_COMPUTED_FACES (f)++;
692 FRAME_COMPUTED_FACES (f)[i] = copy_face (new_face);
693 return i;
694}
695
696
697/* Find a match for NEW_FACE in a FRAME's computed face array, and add
698 it if we don't find one. */
699static int
700intern_computed_face (f, new_face)
701 struct frame *f;
b6d40e46 702 struct face *new_face;
cb637678 703{
7b00de84 704 int len = FRAME_N_COMPUTED_FACES (f);
cb637678
JB
705 int i;
706
7b00de84 707 /* Search for a computed face already on F equivalent to FACE. */
cb637678
JB
708 for (i = 0; i < len; i++)
709 {
7b00de84
JB
710 if (! FRAME_COMPUTED_FACES (f)[i])
711 abort ();
712 if (face_eql (new_face, FRAME_COMPUTED_FACES (f)[i]))
cb637678
JB
713 return i;
714 }
715
716 /* We didn't find one; add a new one. */
7b00de84 717 return new_computed_face (f, new_face);
cb637678
JB
718}
719
7b00de84 720/* Make parameter face id ID valid on frame F. */
cb637678
JB
721
722static void
723ensure_face_ready (f, id)
724 struct frame *f;
725 int id;
726{
7b00de84 727 if (FRAME_N_PARAM_FACES (f) <= id)
cb637678
JB
728 {
729 int n = id + 10;
730 int i;
7b00de84
JB
731 if (!FRAME_N_PARAM_FACES (f))
732 FRAME_PARAM_FACES (f)
cb637678
JB
733 = (struct face **) xmalloc (sizeof (struct face *) * n);
734 else
7b00de84
JB
735 FRAME_PARAM_FACES (f)
736 = (struct face **) xrealloc (FRAME_PARAM_FACES (f),
cb637678
JB
737 sizeof (struct face *) * n);
738
7b00de84
JB
739 bzero (FRAME_PARAM_FACES (f) + FRAME_N_PARAM_FACES (f),
740 (n - FRAME_N_PARAM_FACES (f)) * sizeof (struct face *));
741 FRAME_N_PARAM_FACES (f) = n;
cb637678
JB
742 }
743
7b00de84
JB
744 if (FRAME_PARAM_FACES (f) [id] == 0)
745 FRAME_PARAM_FACES (f) [id] = allocate_face ();
cb637678
JB
746}
747\f
87485d6f 748#ifdef HAVE_X_WINDOWS
867dd159
RS
749/* Return non-zero if FONT1 and FONT2 have the same width.
750 We do not check the height, because we can now deal with
751 different heights.
660ed669 752 We assume that they're both character-cell fonts. */
867dd159 753
660ed669
JB
754int
755same_size_fonts (font1, font2)
756 XFontStruct *font1, *font2;
757{
758 XCharStruct *bounds1 = &font1->min_bounds;
759 XCharStruct *bounds2 = &font2->min_bounds;
760
46407861 761 return (bounds1->width == bounds2->width);
660ed669
JB
762}
763
729425b1 764/* Update the line_height of frame F according to the biggest font in
6717f691 765 any face. Return nonzero if if line_height changes. */
729425b1 766
6717f691 767int
729425b1
RS
768frame_update_line_height (f)
769 FRAME_PTR f;
770{
771 int i;
a8517066
KH
772 int fontset = f->output_data.x->fontset;
773 int biggest = (fontset > 0
774 ? FRAME_FONTSET_DATA (f)->fontset_table[fontset]->height
775 : FONT_HEIGHT (f->output_data.x->font));
729425b1 776
7556890b
RS
777 for (i = 0; i < f->output_data.x->n_param_faces; i++)
778 if (f->output_data.x->param_faces[i] != 0
779 && f->output_data.x->param_faces[i]->font != (XFontStruct *) FACE_DEFAULT)
729425b1 780 {
a8517066
KH
781 int height = ((fontset = f->output_data.x->param_faces[i]->fontset) > 0
782 ? FRAME_FONTSET_DATA (f)->fontset_table[fontset]->height
783 : FONT_HEIGHT (f->output_data.x->param_faces[i]->font));
784
729425b1
RS
785 if (height > biggest)
786 biggest = height;
787 }
788
7556890b 789 if (biggest == f->output_data.x->line_height)
6717f691 790 return 0;
729425b1 791
7556890b 792 f->output_data.x->line_height = biggest;
6717f691 793 return 1;
729425b1 794}
87485d6f 795#endif /* not HAVE_X_WINDOWS */
867dd159 796\f
7b7739b1
JB
797/* Modify face TO by copying from FROM all properties which have
798 nondefault settings. */
867dd159 799
7b7739b1
JB
800static void
801merge_faces (from, to)
802 struct face *from, *to;
803{
867dd159
RS
804 /* Only merge the font if it's the same width as the base font.
805 Otherwise ignore it, since we can't handle it properly. */
68a97335 806 if (from->font != (XFontStruct *) FACE_DEFAULT
68a97335
JB
807 && same_size_fonts (from->font, to->font))
808 to->font = from->font;
a8517066
KH
809 if (from->fontset != -1)
810 to->fontset = from->fontset;
7b7739b1
JB
811 if (from->foreground != FACE_DEFAULT)
812 to->foreground = from->foreground;
813 if (from->background != FACE_DEFAULT)
814 to->background = from->background;
f211082d 815 if (from->stipple != FACE_DEFAULT)
cd0bb842
RS
816 {
817 to->stipple = from->stipple;
818 to->pixmap_h = from->pixmap_h;
819 to->pixmap_w = from->pixmap_w;
820 }
7b7739b1
JB
821 if (from->underline)
822 to->underline = from->underline;
823}
824
660ed669
JB
825/* Set up the basic set of facial parameters, based on the frame's
826 data; all faces are deltas applied to this. */
867dd159 827
660ed669
JB
828static void
829compute_base_face (f, face)
830 FRAME_PTR f;
831 struct face *face;
832{
660ed669 833 face->gc = 0;
cd0bb842
RS
834 face->foreground = FRAME_FOREGROUND_PIXEL (f);
835 face->background = FRAME_BACKGROUND_PIXEL (f);
836 face->font = FRAME_FONT (f);
a8517066 837 face->fontset = -1;
582080c1 838 face->stipple = 0;
660ed669
JB
839 face->underline = 0;
840}
841
867dd159
RS
842/* Return the face ID to use to display a special glyph which selects
843 FACE_CODE as the face ID, assuming that ordinarily the face would
844 be CURRENT_FACE. F is the frame. */
845
846int
847compute_glyph_face (f, face_code, current_face)
848 struct frame *f;
849 int face_code, current_face;
850{
851 struct face face;
852
853 face = *FRAME_COMPUTED_FACES (f)[current_face];
854
855 if (face_code >= 0 && face_code < FRAME_N_PARAM_FACES (f)
856 && FRAME_PARAM_FACES (f) [face_code] != 0)
857 merge_faces (FRAME_PARAM_FACES (f) [face_code], &face);
660ed669 858
867dd159
RS
859 return intern_computed_face (f, &face);
860}
2e16580f
RS
861
862/* Return the face ID to use to display a special glyph which selects
863 FACE_CODE as the face ID, assuming that ordinarily the face would
864 be CURRENT_FACE. F is the frame. */
865
866int
867compute_glyph_face_1 (f, face_name, current_face)
868 struct frame *f;
869 Lisp_Object face_name;
870 int current_face;
871{
872 struct face face;
873
874 face = *FRAME_COMPUTED_FACES (f)[current_face];
875
876 if (!NILP (face_name))
877 {
878 int facecode = face_name_id_number (f, face_name);
879 if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
880 && FRAME_PARAM_FACES (f) [facecode] != 0)
881 merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
882 }
883
884 return intern_computed_face (f, &face);
885}
867dd159 886\f
cb637678 887/* Return the face ID associated with a buffer position POS.
7b7739b1
JB
888 Store into *ENDPTR the position at which a different face is needed.
889 This does not take account of glyphs that specify their own face codes.
f6b98e0b 890 F is the frame in use for display, and W is a window displaying
bc0db68d
RS
891 the current buffer.
892
b349f4fb
RS
893 REGION_BEG, REGION_END delimit the region, so it can be highlighted.
894
895 LIMIT is a position not to scan beyond. That is to limit
6f134486
RS
896 the time this function can take.
897
898 If MOUSE is nonzero, use the character's mouse-face, not its face. */
bc0db68d 899
cb637678 900int
6f134486 901compute_char_face (f, w, pos, region_beg, region_end, endptr, limit, mouse)
7b7739b1 902 struct frame *f;
f211082d 903 struct window *w;
7b7739b1 904 int pos;
bc0db68d 905 int region_beg, region_end;
7b7739b1 906 int *endptr;
b349f4fb 907 int limit;
6f134486 908 int mouse;
7b7739b1
JB
909{
910 struct face face;
b6d40e46 911 Lisp_Object prop, position;
7b7739b1
JB
912 int i, j, noverlays;
913 int facecode;
7b7739b1 914 Lisp_Object *overlay_vec;
f211082d 915 Lisp_Object frame;
f6b98e0b 916 int endpos;
6f134486 917 Lisp_Object propname;
f6b98e0b
JB
918
919 /* W must display the current buffer. We could write this function
920 to use the frame and buffer of W, but right now it doesn't. */
921 if (XBUFFER (w->buffer) != current_buffer)
922 abort ();
f211082d 923
ac22a6c4 924 XSETFRAME (frame, f);
7b7739b1 925
f6b98e0b 926 endpos = ZV;
bc0db68d
RS
927 if (pos < region_beg && region_beg < endpos)
928 endpos = region_beg;
f6b98e0b 929
e0979810 930 XSETFASTINT (position, pos);
6f134486
RS
931
932 if (mouse)
933 propname = Qmouse_face;
934 else
935 propname = Qface;
936
937 prop = Fget_text_property (position, propname, w->buffer);
938
b6d40e46 939 {
b349f4fb 940 Lisp_Object limit1, end;
7b7739b1 941
e0979810 942 XSETFASTINT (limit1, (limit < endpos ? limit : endpos));
6f134486 943 end = Fnext_single_property_change (position, propname, w->buffer, limit1);
b6d40e46
JB
944 if (INTEGERP (end))
945 endpos = XINT (end);
946 }
947
948 {
f6b98e0b 949 int next_overlay;
9516fe94
RS
950 int len;
951
952 /* First try with room for 40 overlays. */
953 len = 40;
954 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
955
7af31819
RS
956 noverlays = overlays_at (pos, 0, &overlay_vec, &len,
957 &next_overlay, (int *) 0);
9516fe94
RS
958
959 /* If there are more than 40,
960 make enough space for all, and try again. */
961 if (noverlays > len)
962 {
963 len = noverlays;
964 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
82277c2f 965 noverlays = overlays_at (pos, 0, &overlay_vec, &len,
7af31819 966 &next_overlay, (int *) 0);
9516fe94 967 }
b6d40e46 968
f6b98e0b
JB
969 if (next_overlay < endpos)
970 endpos = next_overlay;
b6d40e46
JB
971 }
972
973 *endptr = endpos;
7b7739b1
JB
974
975 /* Optimize the default case. */
bc0db68d
RS
976 if (noverlays == 0 && NILP (prop)
977 && !(pos >= region_beg && pos < region_end))
cb637678 978 return 0;
7b7739b1 979
660ed669 980 compute_base_face (f, &face);
7b7739b1 981
4699e6d2
RS
982 if (CONSP (prop))
983 {
984 /* We have a list of faces, merge them in reverse order */
60573a90
RS
985 Lisp_Object length;
986 int len;
4699e6d2
RS
987 Lisp_Object *faces;
988
60573a90
RS
989 length = Fsafe_length (prop);
990 len = XFASTINT (length);
991
4699e6d2
RS
992 /* Put them into an array */
993 faces = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
994 for (j = 0; j < len; j++)
995 {
996 faces[j] = Fcar (prop);
997 prop = Fcdr (prop);
998 }
999 /* So that we can merge them in the reverse order */
1000 for (j = len - 1; j >= 0; j--)
1001 {
1002 facecode = face_name_id_number (f, faces[j]);
1003 if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
1004 && FRAME_PARAM_FACES (f) [facecode] != 0)
1005 merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
1006 }
1007 }
1008 else if (!NILP (prop))
7b7739b1 1009 {
1d9fd7fe 1010 facecode = face_name_id_number (f, prop);
7b00de84
JB
1011 if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
1012 && FRAME_PARAM_FACES (f) [facecode] != 0)
1013 merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
7b7739b1
JB
1014 }
1015
4d6ebff8 1016 noverlays = sort_overlays (overlay_vec, noverlays, w);
7b7739b1
JB
1017
1018 /* Now merge the overlay data in that order. */
7b7739b1
JB
1019 for (i = 0; i < noverlays; i++)
1020 {
6f134486 1021 prop = Foverlay_get (overlay_vec[i], propname);
4699e6d2
RS
1022 if (CONSP (prop))
1023 {
1024 /* We have a list of faces, merge them in reverse order */
60573a90
RS
1025 Lisp_Object length;
1026 int len;
4699e6d2 1027 Lisp_Object *faces;
60573a90
RS
1028
1029 length = Fsafe_length (prop);
1030 len = XFASTINT (length);
4699e6d2
RS
1031
1032 /* Put them into an array */
1033 faces = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1034 for (j = 0; j < len; j++)
1035 {
1036 faces[j] = Fcar (prop);
1037 prop = Fcdr (prop);
1038 }
1039 /* So that we can merge them in the reverse order */
1040 for (j = len - 1; j >= 0; j--)
1041 {
1042 facecode = face_name_id_number (f, faces[j]);
1043 if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
1044 && FRAME_PARAM_FACES (f) [facecode] != 0)
1045 merge_faces (FRAME_PARAM_FACES (f) [facecode], &face);
1046 }
1047 }
1048 else if (!NILP (prop))
7b7739b1
JB
1049 {
1050 Lisp_Object oend;
1051 int oendpos;
1052
1d9fd7fe 1053 facecode = face_name_id_number (f, prop);
7b00de84
JB
1054 if (facecode >= 0 && facecode < FRAME_N_PARAM_FACES (f)
1055 && FRAME_PARAM_FACES (f) [facecode] != 0)
6f134486 1056 merge_faces (FRAME_PARAM_FACES (f)[facecode], &face);
7b7739b1 1057
4d6ebff8 1058 oend = OVERLAY_END (overlay_vec[i]);
7b7739b1 1059 oendpos = OVERLAY_POSITION (oend);
f6b98e0b 1060 if (oendpos < endpos)
7b7739b1
JB
1061 endpos = oendpos;
1062 }
1063 }
1064
bc0db68d
RS
1065 if (pos >= region_beg && pos < region_end)
1066 {
1067 if (region_end < endpos)
1068 endpos = region_end;
1069 if (region_face >= 0 && region_face < next_face_id)
6f134486 1070 merge_faces (FRAME_PARAM_FACES (f)[region_face], &face);
bc0db68d
RS
1071 }
1072
7b7739b1
JB
1073 *endptr = endpos;
1074
7b00de84 1075 return intern_computed_face (f, &face);
f211082d 1076}
867dd159 1077\f
660ed669
JB
1078/* Recompute the GC's for the default and modeline faces.
1079 We call this after changing frame parameters on which those GC's
1080 depend. */
fffc2367 1081
660ed669
JB
1082void
1083recompute_basic_faces (f)
1084 FRAME_PTR f;
1085{
1086 /* If the frame's faces haven't been initialized yet, don't worry about
1087 this stuff. */
7b00de84 1088 if (FRAME_N_PARAM_FACES (f) < 2)
660ed669
JB
1089 return;
1090
1091 BLOCK_INPUT;
1092
1093 if (FRAME_DEFAULT_FACE (f)->gc)
a8517066
KH
1094 {
1095 XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->gc);
1096 XFreeGC (FRAME_X_DISPLAY (f), FRAME_DEFAULT_FACE (f)->non_ascii_gc);
1097 }
660ed669 1098 if (FRAME_MODE_LINE_FACE (f)->gc)
a8517066
KH
1099 {
1100 XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->gc);
1101 XFreeGC (FRAME_X_DISPLAY (f), FRAME_MODE_LINE_FACE (f)->non_ascii_gc);
1102 }
7b00de84
JB
1103 compute_base_face (f, FRAME_DEFAULT_FACE (f));
1104 compute_base_face (f, FRAME_MODE_LINE_FACE (f));
1105
1106 merge_faces (FRAME_DEFAULT_PARAM_FACE (f), FRAME_DEFAULT_FACE (f));
1107 merge_faces (FRAME_MODE_LINE_PARAM_FACE (f), FRAME_MODE_LINE_FACE (f));
1108
42120bc7
RS
1109 intern_face (f, FRAME_DEFAULT_FACE (f));
1110 intern_face (f, FRAME_MODE_LINE_FACE (f));
660ed669
JB
1111
1112 UNBLOCK_INPUT;
1113}
1114
1115
c115973b 1116\f
cb637678 1117/* Lisp interface. */
c115973b
JB
1118
1119DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0,
1120 "")
1121 (frame)
1122 Lisp_Object frame;
1123{
1124 CHECK_FRAME (frame, 0);
1125 return XFRAME (frame)->face_alist;
1126}
1127
1128DEFUN ("set-frame-face-alist", Fset_frame_face_alist, Sset_frame_face_alist,
1129 2, 2, 0, "")
1130 (frame, value)
1131 Lisp_Object frame, value;
1132{
1133 CHECK_FRAME (frame, 0);
1134 XFRAME (frame)->face_alist = value;
1135 return value;
1136}
1137
1138
1139DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
1140 "Create face number FACE-ID on all frames.")
1141 (face_id)
1142 Lisp_Object face_id;
1143{
87485d6f 1144 Lisp_Object rest, frame;
c115973b
JB
1145 int id = XINT (face_id);
1146
f211082d
JB
1147 CHECK_NUMBER (face_id, 0);
1148 if (id < 0 || id >= next_face_id)
1149 error ("Face id out of range");
c115973b 1150
87485d6f 1151 FOR_EACH_FRAME (rest, frame)
c115973b 1152 {
50e3dcf5 1153 if (FRAME_MSDOS_P (XFRAME (frame)) || FRAME_X_P (XFRAME (frame)))
87485d6f 1154 ensure_face_ready (XFRAME (frame), id);
c115973b
JB
1155 }
1156 return Qnil;
1157}
1158
1159
1160DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
1161 Sset_face_attribute_internal, 4, 4, 0, "")
1162 (face_id, attr_name, attr_value, frame)
1163 Lisp_Object face_id, attr_name, attr_value, frame;
1164{
1165 struct face *face;
1166 struct frame *f;
1167 int magic_p;
1168 int id;
53dfb388 1169 int garbaged = 0;
c115973b
JB
1170
1171 CHECK_FRAME (frame, 0);
f211082d 1172 CHECK_NUMBER (face_id, 0);
c115973b
JB
1173 CHECK_SYMBOL (attr_name, 0);
1174
1175 f = XFRAME (frame);
1176 id = XINT (face_id);
f211082d
JB
1177 if (id < 0 || id >= next_face_id)
1178 error ("Face id out of range");
c115973b 1179
50e3dcf5 1180 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
b839cea0 1181 return Qnil;
b6d40e46 1182
c115973b 1183 ensure_face_ready (f, id);
7b00de84 1184 face = FRAME_PARAM_FACES (f) [XFASTINT (face_id)];
c115973b
JB
1185
1186 if (EQ (attr_name, intern ("font")))
1187 {
87485d6f 1188#if defined (MSDOS) && !defined (HAVE_X_WINDOWS)
88d9cecb
RS
1189 /* The one and only font. Must *not* be zero (which
1190 is taken to mean an unused face nowadays). */
1191 face->font = (XFontStruct *)1 ;
87485d6f 1192#else
a8517066
KH
1193 XFontStruct *font;
1194 int fontset;
1195
1196 if (NILP (attr_value))
1197 {
1198 font = (XFontStruct *) FACE_DEFAULT;
1199 fontset = -1;
1200 }
1201 else
1202 {
1203 CHECK_STRING (attr_value, 0);
1204 fontset = fs_query_fontset (f, XSTRING (attr_value)->data);
1205 if (fontset >= 0)
1206 {
1207 struct font_info *fontp;
1208
1209 if (!(fontp = fs_load_font (f, FRAME_X_FONT_TABLE (f),
1210 CHARSET_ASCII, NULL, fontset)))
1211 Fsignal (Qerror,
1212 Fcons (build_string ("ASCII font can't be loaded"),
1213 Fcons (attr_value, Qnil)));
1214 font = (XFontStruct *) (fontp->font);
1215 }
1216 else
1217 font = load_font (f, attr_value);
1218 }
1219
1220 if (face->fontset == -1 && face->font != f->output_data.x->font)
ebc64af3 1221 unload_font (f, face->font);
a8517066 1222
c115973b 1223 face->font = font;
a8517066 1224 face->fontset = fontset;
6717f691
RS
1225 if (frame_update_line_height (f))
1226 x_set_window_size (f, 0, f->width, f->height);
53dfb388
RS
1227 /* Must clear cache, since it might contain the font
1228 we just got rid of. */
1229 garbaged = 1;
87485d6f 1230#endif
c115973b
JB
1231 }
1232 else if (EQ (attr_name, intern ("foreground")))
1233 {
f211082d 1234 unsigned long new_color = load_color (f, attr_value);
c115973b
JB
1235 unload_color (f, face->foreground);
1236 face->foreground = new_color;
53dfb388 1237 garbaged = 1;
c115973b
JB
1238 }
1239 else if (EQ (attr_name, intern ("background")))
1240 {
f211082d 1241 unsigned long new_color = load_color (f, attr_value);
c115973b
JB
1242 unload_color (f, face->background);
1243 face->background = new_color;
53dfb388 1244 garbaged = 1;
c115973b 1245 }
c115973b
JB
1246 else if (EQ (attr_name, intern ("background-pixmap")))
1247 {
cd0bb842
RS
1248 unsigned int w, h;
1249 unsigned long new_pixmap = load_pixmap (f, attr_value, &w, &h);
1250 x_destroy_bitmap (f, face->stipple);
f211082d 1251 face->stipple = new_pixmap;
c115973b
JB
1252 face->pixmap_w = w;
1253 face->pixmap_h = h;
cd0bb842 1254 garbaged = 1;
c115973b 1255 }
c115973b
JB
1256 else if (EQ (attr_name, intern ("underline")))
1257 {
1258 int new = !NILP (attr_value);
1259 face->underline = new;
1260 }
1261 else
1262 error ("unknown face attribute");
1263
7b00de84
JB
1264 if (id == 0 || id == 1)
1265 recompute_basic_faces (f);
c115973b 1266
53dfb388
RS
1267 /* We must redraw the frame whenever any face font or color changes,
1268 because it's possible that a merged (display) face
1269 contains the font or color we just replaced.
1270 And we must inhibit any Expose events until the redraw is done,
1271 since they would try to use the invalid display faces. */
1272 if (garbaged)
f5e278c7
RS
1273 {
1274 SET_FRAME_GARBAGED (f);
1275 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
1276 }
584d0634 1277
c115973b
JB
1278 return Qnil;
1279}
1280
1281DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
1282 0, 0, 0, "")
1283 ()
1284{
1285 return make_number (next_face_id++);
1286}
f211082d
JB
1287
1288/* Return the face id for name NAME on frame FRAME.
1289 (It should be the same for all frames,
1290 but it's as easy to use the "right" frame to look it up
1291 as to use any other one.) */
1292
1d9fd7fe
JB
1293int
1294face_name_id_number (f, name)
1295 FRAME_PTR f;
1296 Lisp_Object name;
f211082d
JB
1297{
1298 Lisp_Object tem;
1299
82411f65 1300 tem = Fcdr (assq_no_quit (name, f->face_alist));
b6d40e46
JB
1301 if (NILP (tem))
1302 return 0;
f211082d
JB
1303 CHECK_VECTOR (tem, 0);
1304 tem = XVECTOR (tem)->contents[2];
1305 CHECK_NUMBER (tem, 0);
1306 return XINT (tem);
1307}
c115973b 1308\f
cb637678
JB
1309/* Emacs initialization. */
1310
c115973b 1311void
f211082d 1312syms_of_xfaces ()
c115973b 1313{
f211082d
JB
1314 Qface = intern ("face");
1315 staticpro (&Qface);
6f134486
RS
1316 Qmouse_face = intern ("mouse-face");
1317 staticpro (&Qmouse_face);
cd0bb842
RS
1318 Qpixmap_spec_p = intern ("pixmap-spec-p");
1319 staticpro (&Qpixmap_spec_p);
f211082d 1320
bc0db68d
RS
1321 DEFVAR_INT ("region-face", &region_face,
1322 "Face number to use to highlight the region\n\
1323The region is highlighted with this face\n\
1324when Transient Mark mode is enabled and the mark is active.");
1325
87485d6f 1326#ifdef HAVE_X_WINDOWS
cd0bb842 1327 defsubr (&Spixmap_spec_p);
87485d6f 1328#endif
c115973b
JB
1329 defsubr (&Sframe_face_alist);
1330 defsubr (&Sset_frame_face_alist);
1331 defsubr (&Smake_face_internal);
1332 defsubr (&Sset_face_attribute_internal);
1333 defsubr (&Sinternal_next_face_id);
1334}
cb637678 1335
87485d6f 1336#endif /* HAVE_FACES */