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