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