comparison src/faces.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* "Face" primitives
2 Copyright (C) 1994 Free Software Foundation, Inc.
3 Copyright (C) 1995 Board of Trustees, University of Illinois.
4 Copyright (C) 1995, 1996 Ben Wing.
5 Copyright (C) 1995 Sun Microsystems, Inc.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 /* Synched up with: Not in FSF. */
25
26 /* Written by Chuck Thompson and Ben Wing,
27 based loosely on old face code by Jamie Zawinski. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "device.h"
34 #include "elhash.h"
35 #include "extents.h"
36 #include "faces.h"
37 #include "frame.h"
38 #include "glyphs.h"
39 #include "hash.h"
40 #include "objects.h"
41 #include "specifier.h"
42 #include "window.h"
43
44 #ifdef HAVE_X_WINDOWS
45 #include "console-x.h"
46 #include "objects-x.h"
47 #include "EmacsFrame.h"
48 #endif /* HAVE_X_WINDOWS */
49
50 #ifdef HAVE_NEXTSTEP
51 #include "console-ns.h"
52 #include "objects-ns.h"
53 #endif /* HAVE_NEXTSTEP */
54
55 /* Qfont, Qdoc_string, Qface defined in general.c */
56 Lisp_Object Qfacep;
57 Lisp_Object Qforeground, Qbackground, Qdisplay_table;
58 /* Qhighlight, Qreverse defined in general.c */
59 Lisp_Object Qbackground_pixmap, Qunderline, Qdim;
60 Lisp_Object Qblinking, Qstrikethru;
61
62 Lisp_Object Qinit_face_from_resources;
63 Lisp_Object Qinit_frame_faces;
64 Lisp_Object Qinit_device_faces;
65 Lisp_Object Qinit_global_faces;
66
67 /* These faces are used directly internally. We use these variables
68 to be able to reference them directly and save the overhead of
69 calling Ffind_face. */
70 Lisp_Object Vdefault_face, Vmodeline_face;
71 Lisp_Object Vleft_margin_face, Vright_margin_face, Vtext_cursor_face;
72 Lisp_Object Vpointer_face;
73
74 /* Qdefault, Qhighlight defined in general.c */
75 Lisp_Object Qmodeline, Qleft_margin, Qright_margin, Qtext_cursor;
76
77 /* In the old implementation Vface_list was a list of the face names,
78 not the faces themselves. We now distinguish between permanent and
79 temporary faces. Permanent faces are kept in a regular hash table,
80 temporary faces in a weak hash table. */
81 Lisp_Object Vpermanent_faces_cache;
82 Lisp_Object Vtemporary_faces_cache;
83
84 Lisp_Object Vbuilt_in_face_specifiers;
85
86
87 static Lisp_Object mark_face (Lisp_Object, void (*) (Lisp_Object));
88 static void print_face (Lisp_Object, Lisp_Object, int);
89 static int face_equal (Lisp_Object, Lisp_Object, int depth);
90 static unsigned long face_hash (Lisp_Object obj, int depth);
91 static Lisp_Object face_getprop (Lisp_Object obj, Lisp_Object prop);
92 static int face_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value);
93 static int face_remprop (Lisp_Object obj, Lisp_Object prop);
94 static Lisp_Object face_plist (Lisp_Object obj);
95 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("face", face,
96 mark_face, print_face, 0, face_equal,
97 face_hash, face_getprop,
98 face_putprop, face_remprop,
99 face_plist, struct Lisp_Face);
100
101 static Lisp_Object
102 mark_face (Lisp_Object obj, void (*markobj) (Lisp_Object))
103 {
104 struct Lisp_Face *face = XFACE (obj);
105
106 ((markobj) (face->name));
107 ((markobj) (face->doc_string));
108
109 ((markobj) (face->foreground));
110 ((markobj) (face->background));
111 ((markobj) (face->font));
112 ((markobj) (face->display_table));
113 ((markobj) (face->background_pixmap));
114 ((markobj) (face->underline));
115 ((markobj) (face->strikethru));
116 ((markobj) (face->highlight));
117 ((markobj) (face->dim));
118 ((markobj) (face->blinking));
119 ((markobj) (face->reverse));
120
121 ((markobj) (face->charsets_warned_about));
122
123 return (face->plist);
124 }
125
126 static void
127 print_face (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
128 {
129 struct Lisp_Face *face = XFACE (obj);
130
131 if (print_readably)
132 {
133 write_c_string ("#s(face name ", printcharfun);
134 print_internal (face->name, printcharfun, 1);
135 write_c_string (")", printcharfun);
136 }
137 else
138 {
139 write_c_string ("#<face ", printcharfun);
140 print_internal (face->name, printcharfun, 1);
141 if (!NILP (face->doc_string))
142 {
143 write_c_string (" ", printcharfun);
144 print_internal (face->doc_string, printcharfun, 1);
145 }
146 write_c_string (">", printcharfun);
147 }
148 }
149
150 /* Faces are equal if all of their display attributes are equal. We
151 don't compare names or doc-strings, because that would make equal
152 be eq.
153
154 This isn't concerned with "unspecified" attributes, that's what
155 #'face-differs-from-default-p is for. */
156 static int
157 face_equal (Lisp_Object o1, Lisp_Object o2, int depth)
158 {
159 struct Lisp_Face *f1 = XFACE (o1);
160 struct Lisp_Face *f2 = XFACE (o2);
161
162 depth++;
163
164 if (!internal_equal (f1->foreground, f2->foreground, depth) ||
165 !internal_equal (f1->background, f2->background, depth) ||
166 !internal_equal (f1->font, f2->font, depth) ||
167 !internal_equal (f1->display_table, f2->display_table, depth) ||
168 !internal_equal (f1->background_pixmap, f2->background_pixmap, depth) ||
169 !internal_equal (f1->underline, f2->underline, depth) ||
170 !internal_equal (f1->strikethru, f2->strikethru, depth) ||
171 !internal_equal (f1->highlight, f2->highlight, depth) ||
172 !internal_equal (f1->dim, f2->dim, depth) ||
173 !internal_equal (f1->blinking, f2->blinking, depth) ||
174 !internal_equal (f1->reverse, f2->reverse, depth) ||
175 plists_differ (f1->plist, f2->plist, 0, 0, depth + 1))
176 return 0;
177
178 return 1;
179 }
180
181 static unsigned long
182 face_hash (Lisp_Object obj, int depth)
183 {
184 struct Lisp_Face *f = XFACE (obj);
185
186 depth++;
187
188 /* No need to hash all of the elements; that would take too long.
189 Just hash the most common ones. */
190 return HASH3 (internal_hash (f->foreground, depth),
191 internal_hash (f->background, depth),
192 internal_hash (f->font, depth));
193 }
194
195 static Lisp_Object
196 face_getprop (Lisp_Object obj, Lisp_Object prop)
197 {
198 struct Lisp_Face *f = XFACE (obj);
199
200 #define FROB(propprop) \
201 do { \
202 if (EQ (prop, Q##propprop)) \
203 { \
204 return f->propprop; \
205 } \
206 } while (0)
207
208 FROB (foreground);
209 FROB (background);
210 FROB (font);
211 FROB (display_table);
212 FROB (background_pixmap);
213 FROB (underline);
214 FROB (strikethru);
215 FROB (highlight);
216 FROB (dim);
217 FROB (blinking);
218 FROB (reverse);
219 FROB (doc_string);
220
221 #undef FROB
222
223 return external_plist_get (&f->plist, prop, 0, ERROR_ME);
224 }
225
226 static int
227 face_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
228 {
229 struct Lisp_Face *f = XFACE (obj);
230
231 #define FROB(propprop) \
232 do { \
233 if (EQ (prop, Q##propprop)) \
234 return 0; \
235 } while (0)
236
237 FROB (foreground);
238 FROB (background);
239 FROB (font);
240 FROB (display_table);
241 FROB (background_pixmap);
242 FROB (underline);
243 FROB (strikethru);
244 FROB (highlight);
245 FROB (dim);
246 FROB (blinking);
247 FROB (reverse);
248
249 #undef FROB
250
251 if (EQ (prop, Qdoc_string))
252 {
253 if (!NILP (value))
254 CHECK_STRING (value);
255 f->doc_string = value;
256 return 1;
257 }
258
259 external_plist_put (&f->plist, prop, value, 0, ERROR_ME);
260 return 1;
261 }
262
263 static int
264 face_remprop (Lisp_Object obj, Lisp_Object prop)
265 {
266 struct Lisp_Face *f = XFACE (obj);
267
268 #define FROB(propprop) \
269 do { \
270 if (EQ (prop, Q##propprop)) \
271 return -1; \
272 } while (0)
273
274 FROB (foreground);
275 FROB (background);
276 FROB (font);
277 FROB (display_table);
278 FROB (background_pixmap);
279 FROB (underline);
280 FROB (strikethru);
281 FROB (highlight);
282 FROB (dim);
283 FROB (blinking);
284 FROB (reverse);
285
286 #undef FROB
287
288 if (EQ (prop, Qdoc_string))
289 {
290 f->doc_string = Qnil;
291 return 1;
292 }
293
294 return external_remprop (&f->plist, prop, 0, ERROR_ME);
295 }
296
297 static Lisp_Object
298 face_plist (Lisp_Object obj)
299 {
300 struct Lisp_Face *f = XFACE (obj);
301 Lisp_Object result = Qnil;
302
303 #define FROB(propprop) \
304 do { \
305 /* backwards order; we reverse it below */ \
306 result = Fcons (f->propprop, Fcons (Q##propprop, result)); \
307 } while (0)
308
309 FROB (foreground);
310 FROB (background);
311 FROB (font);
312 FROB (display_table);
313 FROB (background_pixmap);
314 FROB (underline);
315 FROB (strikethru);
316 FROB (highlight);
317 FROB (dim);
318 FROB (blinking);
319 FROB (reverse);
320
321 #undef FROB
322 return nconc2 (Fnreverse (result), f->plist);
323 }
324
325
326 /************************************************************************/
327 /* face read syntax */
328 /************************************************************************/
329
330 static int
331 face_name_validate (Lisp_Object keyword, Lisp_Object value,
332 Error_behavior errb)
333 {
334 if (ERRB_EQ (errb, ERROR_ME))
335 {
336 CHECK_SYMBOL (value);
337 return 1;
338 }
339
340 return SYMBOLP (value);
341 }
342
343 static int
344 face_validate (Lisp_Object data, Error_behavior errb)
345 {
346 int name_seen = 0;
347 Lisp_Object valw;
348
349 data = Fcdr (data); /* skip over Qface */
350 while (!NILP (data))
351 {
352 Lisp_Object keyw = Fcar (data);
353
354 data = Fcdr (data);
355 valw = Fcar (data);
356 data = Fcdr (data);
357 if (EQ (keyw, Qname))
358 {
359 if (name_seen)
360 {
361 maybe_signal_simple_error ("Duplicate face name given", valw,
362 Qface, errb);
363 return 0;
364 }
365 name_seen = 1;
366 }
367 else
368 abort ();
369 }
370
371 if (!name_seen)
372 {
373 maybe_error (Qface, errb, "No face name given");
374 return 0;
375 }
376
377 if (NILP (Ffind_face (valw)))
378 {
379 maybe_signal_simple_error ("No such face", valw, Qface, errb);
380 return 0;
381 }
382
383 return 1;
384 }
385
386 static Lisp_Object
387 face_instantiate (Lisp_Object data)
388 {
389 return Fget_face (Fcar (Fcdr (data)));
390 }
391
392
393 /****************************************************************************
394 * utility functions *
395 ****************************************************************************/
396
397 static void
398 reset_face (struct Lisp_Face *f)
399 {
400 f->name = Qnil;
401 f->doc_string = Qnil;
402 f->dirty = 0;
403 f->foreground = Qnil;
404 f->background = Qnil;
405 f->font = Qnil;
406 f->display_table = Qnil;
407 f->background_pixmap = Qnil;
408 f->underline = Qnil;
409 f->strikethru = Qnil;
410 f->highlight = Qnil;
411 f->dim = Qnil;
412 f->blinking = Qnil;
413 f->reverse = Qnil;
414 f->plist = Qnil;
415 f->charsets_warned_about = Qnil;
416 }
417
418 static struct Lisp_Face *
419 allocate_face (void)
420 {
421 struct Lisp_Face *result =
422 alloc_lcrecord (sizeof (struct Lisp_Face), lrecord_face);
423
424 reset_face (result);
425 return result;
426 }
427
428
429 /* We store the faces in hash tables with the names as the key and the
430 actual face object as the value. Occasionally we need to use them
431 in a list format. These routines provide us with that. */
432 struct face_list_closure
433 {
434 Lisp_Object *face_list;
435 };
436
437 static void
438 add_face_to_list_mapper (CONST void *hash_key, void *hash_contents,
439 void *face_list_closure)
440 {
441 /* This function can GC */
442 Lisp_Object key, contents;
443 Lisp_Object *face_list;
444 struct face_list_closure *fcl = face_list_closure;
445 CVOID_TO_LISP (key, hash_key);
446 VOID_TO_LISP (contents, hash_contents);
447 face_list = fcl->face_list;
448
449 *face_list = Fcons (XFACE (contents)->name, *face_list);
450 }
451
452 static Lisp_Object
453 faces_list_internal (Lisp_Object list)
454 {
455 Lisp_Object face_list = Qnil;
456 struct gcpro gcpro1;
457 struct face_list_closure face_list_closure;
458
459 GCPRO1 (face_list);
460 face_list_closure.face_list = &face_list;
461 elisp_maphash (add_face_to_list_mapper, list, &face_list_closure);
462 UNGCPRO;
463
464 return face_list;
465 }
466
467 static Lisp_Object
468 permanent_faces_list (void)
469 {
470 return faces_list_internal (Vpermanent_faces_cache);
471 }
472
473 static Lisp_Object
474 temporary_faces_list (void)
475 {
476 return faces_list_internal (Vtemporary_faces_cache);
477 }
478
479
480 static void
481 mark_face_as_clean_mapper (CONST void *hash_key, void *hash_contents,
482 void *flag_closure)
483 {
484 /* This function can GC */
485 Lisp_Object key, contents;
486 int *flag = flag_closure;
487 CVOID_TO_LISP (key, hash_key);
488 VOID_TO_LISP (contents, hash_contents);
489 XFACE (contents)->dirty = *flag;
490 }
491
492 static void
493 mark_all_faces_internal (int flag)
494 {
495 elisp_maphash (mark_face_as_clean_mapper, Vpermanent_faces_cache, &flag);
496 elisp_maphash (mark_face_as_clean_mapper, Vtemporary_faces_cache, &flag);
497 }
498
499 void
500 mark_all_faces_as_clean (void)
501 {
502 mark_all_faces_internal (0);
503 }
504
505 /* #### OBSOLETE ME, PLEASE. Maybe. Maybe this is just as good as
506 any other solution. */
507 struct face_inheritance_closure
508 {
509 Lisp_Object face;
510 Lisp_Object property;
511 };
512
513 static void
514 update_inheritance_mapper_internal (Lisp_Object cur_face,
515 Lisp_Object inh_face,
516 Lisp_Object property)
517 {
518 /* #### fix this function */
519 Lisp_Object elt = Qnil;
520 struct gcpro gcpro1;
521
522 GCPRO1 (elt);
523
524 for (elt = FACE_PROPERTY_SPEC_LIST (cur_face, property, Qall);
525 !NILP (elt);
526 elt = XCDR (elt))
527 {
528 Lisp_Object locale, values;
529
530 locale = XCAR (XCAR (elt));
531 values = XCDR (XCAR (elt));
532
533 for (; !NILP (values); values = XCDR (values))
534 {
535 Lisp_Object value = XCDR (XCAR (values));
536 if (VECTORP (value) && XVECTOR (value)->size)
537 {
538 if (EQ (Ffind_face (vector_data (XVECTOR (value))[0]), inh_face))
539 Fset_specifier_dirty_flag
540 (FACE_PROPERTY_SPECIFIER (inh_face, property));
541 }
542 }
543 }
544
545 UNGCPRO;
546 }
547
548 static void
549 update_face_inheritance_mapper (CONST void *hash_key, void *hash_contents,
550 void *face_inheritance_closure)
551 {
552 Lisp_Object key, contents;
553 struct face_inheritance_closure *fcl = face_inheritance_closure;
554
555 CVOID_TO_LISP (key, hash_key);
556 VOID_TO_LISP (contents, hash_contents);
557
558 if (EQ (fcl->property, Qfont))
559 {
560 update_inheritance_mapper_internal (contents, fcl->face, Qfont);
561 }
562 else if (EQ (fcl->property, Qforeground)
563 || EQ (fcl->property, Qbackground))
564 {
565 update_inheritance_mapper_internal (contents, fcl->face, Qforeground);
566 update_inheritance_mapper_internal (contents, fcl->face, Qbackground);
567 }
568 else if (EQ (fcl->property, Qunderline)
569 || EQ (fcl->property, Qstrikethru)
570 || EQ (fcl->property, Qhighlight)
571 || EQ (fcl->property, Qdim)
572 || EQ (fcl->property, Qblinking)
573 || EQ (fcl->property, Qreverse))
574 {
575 update_inheritance_mapper_internal (contents, fcl->face, Qunderline);
576 update_inheritance_mapper_internal (contents, fcl->face, Qstrikethru);
577 update_inheritance_mapper_internal (contents, fcl->face, Qhighlight);
578 update_inheritance_mapper_internal (contents, fcl->face, Qdim);
579 update_inheritance_mapper_internal (contents, fcl->face, Qblinking);
580 update_inheritance_mapper_internal (contents, fcl->face, Qreverse);
581 }
582 }
583
584 static void
585 update_faces_inheritance (Lisp_Object face, Lisp_Object property)
586 {
587 struct face_inheritance_closure face_inheritance_closure;
588 struct gcpro gcpro1, gcpro2;
589
590 GCPRO2 (face, property);
591 face_inheritance_closure.face = face;
592 face_inheritance_closure.property = property;
593
594 elisp_maphash (update_face_inheritance_mapper, Vpermanent_faces_cache,
595 &face_inheritance_closure);
596 elisp_maphash (update_face_inheritance_mapper, Vtemporary_faces_cache,
597 &face_inheritance_closure);
598
599 UNGCPRO;
600 }
601
602 Lisp_Object
603 face_property_matching_instance (Lisp_Object face, Lisp_Object property,
604 Lisp_Object charset, Lisp_Object domain,
605 Error_behavior errb, int no_fallback,
606 Lisp_Object depth)
607 {
608 Lisp_Object retval =
609 specifier_instance_no_quit (Fget (face, property, Qnil), charset,
610 domain, errb, no_fallback, depth);
611
612 if (UNBOUNDP (retval) && !no_fallback)
613 {
614 if (EQ (property, Qfont))
615 {
616 if (NILP (memq_no_quit (charset,
617 XFACE (face)->charsets_warned_about)))
618 {
619 warn_when_safe (Qfont, Qwarning,
620 "Unable to instantiate font for face %s",
621 string_data (symbol_name
622 (XSYMBOL (XFACE (face)->name))));
623 XFACE (face)->charsets_warned_about =
624 Fcons (charset, XFACE (face)->charsets_warned_about);
625 }
626 retval = Vthe_null_font_instance;
627 }
628 }
629
630 return retval;
631 }
632
633
634 DEFUN ("facep", Ffacep, Sfacep, 1, 1, 0 /*
635 Return non-nil if OBJECT is a face.
636 */ )
637 (object)
638 Lisp_Object object;
639 {
640 return (FACEP (object) ? Qt : Qnil);
641 }
642
643 DEFUN ("find-face", Ffind_face, Sfind_face, 1, 1, 0 /*
644 Retrieve the face of the given name.
645 If FACE-OR-NAME is a face object, it is simply returned.
646 Otherwise, FACE-OR-NAME should be a symbol. If there is no such face,
647 nil is returned. Otherwise the associated face object is returned.
648 */ )
649 (face_or_name)
650 Lisp_Object face_or_name;
651 {
652 Lisp_Object retval;
653
654 if (FACEP (face_or_name))
655 return face_or_name;
656 CHECK_SYMBOL (face_or_name);
657
658 /* Check if the name represents a permanent face. */
659 retval = Fgethash (face_or_name, Vpermanent_faces_cache, Qnil);
660 if (!NILP (retval))
661 return retval;
662
663 /* Check if the name represents a temporary face. */
664 return Fgethash (face_or_name, Vtemporary_faces_cache, Qnil);
665 }
666
667 DEFUN ("get-face", Fget_face, Sget_face, 1, 1, 0 /*
668 Retrieve the face of the given name.
669 Same as `find-face' except an error is signalled if there is no such
670 face instead of returning nil.
671 */ )
672 (name)
673 Lisp_Object name;
674 {
675 Lisp_Object face = Ffind_face (name);
676
677 if (NILP (face))
678 signal_simple_error ("No such face", name);
679 return face;
680 }
681
682 DEFUN ("face-name", Fface_name, Sface_name, 1, 1, 0 /*
683 Return the name of the given face.
684 */ )
685 (face)
686 Lisp_Object face;
687 {
688 return (XFACE (Fget_face (face))->name);
689 }
690
691 DEFUN ("built-in-face-specifiers", Fbuilt_in_face_specifiers,
692 Sbuilt_in_face_specifiers, 0, 0, 0 /*
693 Return a list of all built-in face specifier properties.
694 Don't modify this list!
695 */ )
696 ()
697 {
698 return Vbuilt_in_face_specifiers;
699 }
700
701 /* These values are retrieved so often that we make a special
702 function.
703 */
704
705 void
706 default_face_font_info (Lisp_Object domain, int *ascent, int *descent,
707 int *height, int *width, int *proportional_p)
708 {
709 Lisp_Object font_instance;
710
711 if (noninteractive)
712 {
713 if (ascent)
714 *ascent = 1;
715 if (descent)
716 *descent = 0;
717 if (height)
718 *height = 1;
719 if (width)
720 *width = 1;
721 if (proportional_p)
722 *proportional_p = 0;
723 return;
724 }
725
726 /* We use ASCII here. This is probably reasonable because the
727 people calling this function are using the resulting values to
728 come up with overall sizes for windows and frames. */
729 if (WINDOWP (domain))
730 {
731 struct face_cachel *cachel;
732 struct window *w = XWINDOW (domain);
733
734 /* #### It's possible for this function to get called when the
735 face cachels have not been initialized. I don't know why. */
736 if (!Dynarr_length (w->face_cachels))
737 reset_face_cachels (w);
738 cachel = WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
739 font_instance = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
740 }
741 else
742 {
743 font_instance = FACE_FONT (Vdefault_face, domain, Vcharset_ascii);
744 }
745
746 if (height)
747 *height = XFONT_INSTANCE (font_instance)->height;
748 if (width)
749 *width = XFONT_INSTANCE (font_instance)->width;
750 if (ascent)
751 *ascent = XFONT_INSTANCE (font_instance)->ascent;
752 if (descent)
753 *descent = XFONT_INSTANCE (font_instance)->descent;
754 if (proportional_p)
755 *proportional_p = XFONT_INSTANCE (font_instance)->proportional_p;
756 }
757
758 void
759 default_face_height_and_width (Lisp_Object domain,
760 int *height, int *width)
761 {
762 default_face_font_info (domain, 0, 0, height, width, 0);
763 }
764
765 DEFUN ("face-list", Fface_list, Sface_list, 0, 1, 0 /*
766 Return a list of the names of all defined faces.
767 If TEMPORARY is nil, only the permanent faces are included.
768 If it is t, only the temporary faces are included. If it is any
769 other non-nil value both permanent and temporary are included.
770 */ )
771 (temporary)
772 Lisp_Object temporary;
773 {
774 Lisp_Object face_list = Qnil;
775
776 /* Added the permanent faces, if requested. */
777 if (NILP (temporary) || !EQ (Qt, temporary))
778 face_list = permanent_faces_list ();
779
780 if (!NILP (temporary))
781 {
782 struct gcpro gcpro1;
783 GCPRO1 (face_list);
784 face_list = nconc2 (face_list, temporary_faces_list ());
785 UNGCPRO;
786 }
787
788 return face_list;
789 }
790
791 DEFUN ("make-face", Fmake_face, Smake_face, 1, 3, 0 /*
792 Defines and returns a new FACE described by DOC-STRING.
793 You can modify the font, color, etc of a face with the set-face- functions.
794 If the face already exists, it is unmodified.
795 If TEMPORARY is non-nil, this face will cease to exist if not in use.
796 */ )
797 (name, doc_string, temporary)
798 Lisp_Object name, doc_string, temporary;
799 {
800 /* This function can GC if initialized is non-zero */
801 struct Lisp_Face *f;
802 Lisp_Object face;
803
804 CHECK_SYMBOL (name);
805 if (!NILP (doc_string))
806 CHECK_STRING (doc_string);
807
808 face = Ffind_face (name);
809 if (!NILP (face))
810 return face;
811
812 f = allocate_face ();
813 XSETFACE (face, f);
814
815 f->name = name;
816 f->doc_string = doc_string;
817 f->foreground = Fmake_specifier (Qcolor);
818 set_color_attached_to (f->foreground, face, Qforeground);
819 f->background = Fmake_specifier (Qcolor);
820 set_color_attached_to (f->background, face, Qbackground);
821 f->font = Fmake_specifier (Qfont);
822 set_font_attached_to (f->font, face, Qfont);
823 f->background_pixmap = Fmake_specifier (Qimage);
824 set_image_attached_to (f->background_pixmap, face, Qbackground_pixmap);
825 /* #### need a special display-table specifier */
826 f->display_table = Fmake_specifier (Qgeneric);
827 f->underline = Fmake_specifier (Qface_boolean);
828 set_face_boolean_attached_to (f->underline, face, Qunderline);
829 f->strikethru = Fmake_specifier (Qface_boolean);
830 set_face_boolean_attached_to (f->strikethru, face, Qstrikethru);
831 f->highlight = Fmake_specifier (Qface_boolean);
832 set_face_boolean_attached_to (f->highlight, face, Qhighlight);
833 f->dim = Fmake_specifier (Qface_boolean);
834 set_face_boolean_attached_to (f->dim, face, Qdim);
835 f->blinking = Fmake_specifier (Qface_boolean);
836 set_face_boolean_attached_to (f->blinking, face, Qblinking);
837 f->reverse = Fmake_specifier (Qface_boolean);
838 set_face_boolean_attached_to (f->reverse, face, Qreverse);
839 if (!NILP (Vdefault_face))
840 {
841 /* If the default face has already been created, set it as
842 the default fallback specifier for all the specifiers we
843 just created. This implements the standard "all faces
844 inherit from default" behavior. */
845 set_specifier_fallback (f->foreground,
846 Fget (Vdefault_face, Qforeground, Qunbound));
847 set_specifier_fallback (f->background,
848 Fget (Vdefault_face, Qbackground, Qunbound));
849 set_specifier_fallback (f->font,
850 Fget (Vdefault_face, Qfont, Qunbound));
851 set_specifier_fallback (f->background_pixmap,
852 Fget (Vdefault_face, Qbackground_pixmap,
853 Qunbound));
854 set_specifier_fallback (f->display_table,
855 Fget (Vdefault_face, Qdisplay_table, Qunbound));
856 set_specifier_fallback (f->underline,
857 Fget (Vdefault_face, Qunderline, Qunbound));
858 set_specifier_fallback (f->strikethru,
859 Fget (Vdefault_face, Qstrikethru, Qunbound));
860 set_specifier_fallback (f->highlight,
861 Fget (Vdefault_face, Qhighlight, Qunbound));
862 set_specifier_fallback (f->dim,
863 Fget (Vdefault_face, Qdim, Qunbound));
864 set_specifier_fallback (f->blinking,
865 Fget (Vdefault_face, Qblinking, Qunbound));
866 set_specifier_fallback (f->reverse,
867 Fget (Vdefault_face, Qreverse, Qunbound));
868 }
869
870 /* Add the face to the appropriate list. */
871 if (NILP (temporary))
872 Fputhash (name, face, Vpermanent_faces_cache);
873 else
874 Fputhash (name, face, Vtemporary_faces_cache);
875
876 /* Note that it's OK if we dump faces.
877 When we start up again when we're not noninteractive,
878 `init-global-faces' is called and it resources all
879 existing faces. */
880 if (initialized && !noninteractive)
881 {
882 struct gcpro gcpro1, gcpro2;
883
884 GCPRO2 (name, face);
885 call1 (Qinit_face_from_resources, name);
886 UNGCPRO;
887 }
888
889 return face;
890 }
891
892
893 /*****************************************************************************
894 initialization code
895 ****************************************************************************/
896
897 void
898 init_global_faces (struct device *d)
899 {
900 /* When making the initial terminal device, there is no Lisp code
901 loaded, so we can't do this. */
902 if (initialized && !noninteractive)
903 {
904 call_critical_lisp_code (d, Qinit_global_faces, Qnil);
905 }
906 }
907
908 void
909 init_device_faces (struct device *d)
910 {
911 /* When making the initial terminal device, there is no Lisp code
912 loaded, so we can't do this. */
913 if (initialized)
914 {
915 Lisp_Object tdevice;
916 XSETDEVICE (tdevice, d);
917 call_critical_lisp_code (d, Qinit_device_faces, tdevice);
918 }
919 }
920
921 void
922 init_frame_faces (struct frame *frm)
923 {
924 /* When making the initial terminal device, there is no Lisp code
925 loaded, so we can't do this. */
926 if (initialized)
927 {
928 Lisp_Object tframe;
929 XSETFRAME (tframe, frm);
930
931 /* DO NOT change the selected frame here. If the debugger goes off
932 it will try and display on the frame being created, but it is not
933 ready for that yet and a horrible death will occur. Any random
934 code depending on the selected-frame as an implicit arg should be
935 tracked down and shot. For the benefit of the one known,
936 xpm-color-symbols, make-frame sets the variable
937 Vframe_being_created to the frame it is making and sets it to nil
938 when done. Internal functions that this could trigger which are
939 currently depending on selected-frame should use this instead. It
940 is not currently visible at the lisp level. */
941 call_critical_lisp_code (XDEVICE (FRAME_DEVICE (frm)),
942 Qinit_frame_faces, tframe);
943 }
944 }
945
946
947 /****************************************************************************
948 * face cache element functions *
949 ****************************************************************************/
950
951 /*
952
953 #### Here is a description of how the face cache elements ought
954 to be redone. It is *NOT* how they work currently:
955
956 However, when I started to go about implementing this, I realized
957 that there are all sorts of subtle problems with cache coherency
958 that are coming up. As it turns out, these problems don't
959 manifest themselves now due to the brute-force "kill 'em all"
960 approach to cache invalidation when faces change; but if this
961 is ever made smarter, these problems are going to come up, and
962 some of them are very non-obvious.
963
964 I'm thinking of redoing the cache code a bit to avoid these
965 coherency problems. The bulk of the problems will arise because
966 the current display structures have simple indices into the
967 face cache, but the cache can be changed at various times,
968 which could make the current display structures incorrect.
969 I guess the dirty and updated flags are an attempt to fix
970 this, but this approach doesn't really work.
971
972 Here's an approach that should keep things clean and unconfused:
973
974 1) Imagine a "virtual face cache" that can grow arbitrarily
975 big and for which the only thing allowed is to add new
976 elements. Existing elements cannot be removed or changed.
977 This way, any pointers in the existing redisplay structure
978 into the cache never get screwed up. (This is important
979 because even if a cache element is out of date, if there's
980 a pointer to it then its contents still accurately describe
981 the way the text currently looks on the screen.)
982 2) Each element in the virtual cache either describes exactly
983 one face, or describes the merger of a number of faces
984 by some process. In order to simplify things, for mergers
985 we do not record which faces or ordering was used, but
986 simply that this cache element is the result of merging.
987 Unlike the current implementation, it's important that a
988 single cache element not be used to both describe a
989 single face and describe a merger, even if all the property
990 values are the same.
991 3) Each cache element can be clean or dirty. "Dirty" means
992 that the face that the element points to has been changed;
993 this gets set at the time the face is changed. This
994 way, when looking up a value in the cache, you can determine
995 whether it's out of date or not. For merged faces it
996 does not matter -- we don't record the faces or priority
997 used to create the merger, so it's impossible to look up
998 one of these faces. We have to recompute it each time.
999 Luckily, this is fine -- doing the merge is much
1000 less expensive than recomputing the properties of a
1001 single face.
1002 4) For each cache element, we keep a hash value. (In order
1003 to hash the boolean properties, we convert each of them
1004 into a different large prime number so that the hashing works
1005 well.) This allows us, when comparing runes, to properly
1006 determine whether the face for that rune has changed.
1007 This will be especially important for TTY's, where there
1008 aren't that many faces and minimizing redraw is very
1009 important.
1010 5) We can't actually keep an infinite cache, but that doesn't
1011 really matter that much. The only elements we care about
1012 are those that are used by either the current or desired
1013 display structs. Therefore, we keep a per-window
1014 redisplay iteration number, and mark each element with
1015 that number as we use it. Just after outputting the
1016 window and synching the redisplay structs, we go through
1017 the cache and invalidate all elements that are not clean
1018 elements referring to a particular face and that do not
1019 have an iteration number equal to the current one. We
1020 keep them in a chain, and use them to allocate new
1021 elements when possible instead of increasing the Dynarr.
1022
1023 */
1024
1025 /* mark for GC a dynarr of face cachels. */
1026
1027 void
1028 mark_face_cachels (face_cachel_dynarr *elements,
1029 void (*markobj) (Lisp_Object))
1030 {
1031 int elt;
1032
1033 if (!elements)
1034 return;
1035
1036 for (elt = 0; elt < Dynarr_length (elements); elt++)
1037 {
1038 struct face_cachel *cachel = Dynarr_atp (elements, elt);
1039
1040 {
1041 int i;
1042
1043 for (i = 0; i < NUM_LEADING_BYTES; i++)
1044 if (!NILP (cachel->font[i]) && !UNBOUNDP (cachel->font[i]))
1045 ((markobj) (cachel->font[i]));
1046 }
1047 ((markobj) (cachel->face));
1048 ((markobj) (cachel->foreground));
1049 ((markobj) (cachel->background));
1050 ((markobj) (cachel->display_table));
1051 ((markobj) (cachel->background_pixmap));
1052 }
1053 }
1054
1055 /* ensure that the given cachel contains an updated font value for
1056 the given charset. Return the updated font value. */
1057
1058 Lisp_Object
1059 ensure_face_cachel_contains_charset (struct face_cachel *cachel,
1060 Lisp_Object domain, Lisp_Object charset)
1061 {
1062 Lisp_Object new_val;
1063 Lisp_Object face = cachel->face;
1064 int bound = 1;
1065 int offs = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE;
1066
1067 if (!UNBOUNDP (cachel->font[offs])
1068 && cachel->font_updated[offs])
1069 return cachel->font[offs];
1070
1071 if (UNBOUNDP (face))
1072 {
1073 /* a merged face. */
1074 int i;
1075 struct window *w = XWINDOW (domain);
1076
1077 new_val = Qunbound;
1078 cachel->font_specified[offs] = 0;
1079 for (i = 0; i < cachel->nfaces; i++)
1080 {
1081 struct face_cachel *oth;
1082
1083 oth = Dynarr_atp (w->face_cachels,
1084 FACE_CACHEL_FINDEX_UNSAFE (cachel, i));
1085 /* Tout le monde aime la recursion */
1086 ensure_face_cachel_contains_charset (oth, domain, charset);
1087
1088 if (oth->font_specified[offs])
1089 {
1090 new_val = oth->font[offs];
1091 cachel->font_specified[offs] = 1;
1092 break;
1093 }
1094 }
1095
1096 if (!cachel->font_specified[offs])
1097 /* need to do the default face. */
1098 {
1099 struct face_cachel *oth =
1100 Dynarr_atp (w->face_cachels, DEFAULT_INDEX);
1101 ensure_face_cachel_contains_charset (oth, domain, charset);
1102
1103 new_val = oth->font[offs];
1104 }
1105
1106 if (!UNBOUNDP (cachel->font[offs]) && !EQ (cachel->font[offs], new_val))
1107 cachel->dirty = 1;
1108 cachel->font_updated[offs] = 1;
1109 cachel->font[offs] = new_val;
1110 return new_val;
1111 }
1112
1113 new_val = face_property_matching_instance (face, Qfont, charset, domain,
1114 /* #### look into ERROR_ME_NOT */
1115 ERROR_ME_NOT, 1, Qzero);
1116 if (UNBOUNDP (new_val))
1117 {
1118 bound = 0;
1119 new_val = face_property_matching_instance (face, Qfont,
1120 charset, domain,
1121 /* #### look into
1122 ERROR_ME_NOT */
1123 ERROR_ME_NOT, 0, Qzero);
1124 }
1125 if (!UNBOUNDP (cachel->font[offs]) && !EQ (new_val, cachel->font[offs]))
1126 cachel->dirty = 1;
1127 cachel->font_updated[offs] = 1;
1128 cachel->font[offs] = new_val;
1129 cachel->font_specified[offs] = (bound || EQ (face, Vdefault_face));
1130 return new_val;
1131 }
1132
1133 /* Ensure that the given cachel contains updated fonts for all
1134 the charsets specified. */
1135
1136 void
1137 ensure_face_cachel_complete (struct face_cachel *cachel,
1138 Lisp_Object domain, unsigned char *charsets)
1139 {
1140 int i;
1141
1142 for (i = 0; i < NUM_LEADING_BYTES; i++)
1143 if (charsets[i])
1144 {
1145 Lisp_Object charset;
1146
1147 charset = CHARSET_BY_LEADING_BYTE (i + MIN_LEADING_BYTE);
1148 assert (CHARSETP (charset));
1149 ensure_face_cachel_contains_charset (cachel, domain, charset);
1150 }
1151 }
1152
1153 void
1154 face_cachel_charset_font_metric_info (struct face_cachel *cachel,
1155 unsigned char *charsets,
1156 struct font_metric_info *fm)
1157 {
1158 int i;
1159
1160 fm->width = 1;
1161 fm->height = fm->ascent = 1;
1162 fm->descent = 0;
1163 fm->proportional_p = 0;
1164
1165 for (i = 0; i < NUM_LEADING_BYTES; i++)
1166 {
1167 if (charsets[i])
1168 {
1169 Lisp_Object charset;
1170 Lisp_Object font_instance;
1171 struct Lisp_Font_Instance *fi;
1172
1173 charset = CHARSET_BY_LEADING_BYTE (i + MIN_LEADING_BYTE);
1174 assert (CHARSETP (charset));
1175 font_instance = FACE_CACHEL_FONT (cachel, charset);
1176 assert (FONT_INSTANCEP (font_instance));
1177 fi = XFONT_INSTANCE (font_instance);
1178 fm->ascent = max ((int) fi->ascent, (int) fm->ascent);
1179 fm->descent = max ((int) fi->descent, (int) fm->descent);
1180 fm->height = fm->ascent + fm->descent;
1181 if (fi->proportional_p)
1182 fm->proportional_p = 1;
1183 if (EQ (charset, Vcharset_ascii))
1184 fm->width = fi->width;
1185 }
1186 }
1187 }
1188
1189 /* Called when the updated flag has been cleared on a cachel. */
1190
1191 void
1192 update_face_cachel_data (struct face_cachel *cachel,
1193 Lisp_Object domain,
1194 Lisp_Object face)
1195 {
1196 if (XFACE (face)->dirty || UNBOUNDP (cachel->face))
1197 {
1198 int default_face = EQ (face, Vdefault_face);
1199 cachel->face = face;
1200
1201 /* We normally only set the _specified flags if the value was
1202 actually bound. The exception is for the default face where
1203 we always set it since it is the ultimate fallback. */
1204
1205 #define FROB(field) \
1206 do { \
1207 Lisp_Object new_val = \
1208 FACE_PROPERTY_INSTANCE (face, Q##field, domain, 1, Qzero); \
1209 int bound = 1; \
1210 if (UNBOUNDP (new_val)) \
1211 { \
1212 bound = 0; \
1213 new_val = FACE_PROPERTY_INSTANCE (face, Q##field, domain, 0, Qzero); \
1214 } \
1215 if (!EQ (new_val, cachel->field)) \
1216 { \
1217 cachel->field = new_val; \
1218 cachel->dirty = 1; \
1219 } \
1220 cachel->field##_specified = (bound || default_face); \
1221 } while (0)
1222
1223 FROB (foreground);
1224 FROB (background);
1225 FROB (display_table);
1226 FROB (background_pixmap);
1227 #undef FROB
1228
1229 ensure_face_cachel_contains_charset (cachel, domain, Vcharset_ascii);
1230
1231 #define FROB(field) \
1232 do { \
1233 Lisp_Object new_val = \
1234 FACE_PROPERTY_INSTANCE (face, Q##field, domain, 1, Qzero); \
1235 int bound = 1; \
1236 int new_val_int; \
1237 if (UNBOUNDP (new_val)) \
1238 { \
1239 bound = 0; \
1240 new_val = FACE_PROPERTY_INSTANCE (face, Q##field, domain, 0, Qzero); \
1241 } \
1242 new_val_int = EQ (new_val, Qt); \
1243 if (cachel->field != new_val_int) \
1244 { \
1245 cachel->field = new_val_int; \
1246 cachel->dirty = 1; \
1247 } \
1248 cachel->field##_specified = bound; \
1249 } while (0)
1250
1251 FROB (underline);
1252 FROB (strikethru);
1253 FROB (highlight);
1254 FROB (dim);
1255 FROB (reverse);
1256 FROB (blinking);
1257 #undef FROB
1258 }
1259
1260 cachel->updated = 1;
1261 }
1262
1263 /* Merge the cachel identified by FINDEX in window W into the given
1264 cachel. */
1265
1266 static void
1267 merge_face_cachel_data (struct window *w, face_index findex,
1268 struct face_cachel *cachel)
1269 {
1270 #define FINDEX_FIELD(field) \
1271 Dynarr_atp (w->face_cachels, findex)->field
1272
1273 #define FROB(field) \
1274 do { \
1275 if (!cachel->field##_specified && FINDEX_FIELD (field##_specified)) \
1276 { \
1277 cachel->field = FINDEX_FIELD (field); \
1278 cachel->field##_specified = 1; \
1279 cachel->dirty = 1; \
1280 } \
1281 } while (0)
1282
1283 FROB (foreground);
1284 FROB (background);
1285 FROB (display_table);
1286 FROB (background_pixmap);
1287 FROB (underline);
1288 FROB (strikethru);
1289 FROB (highlight);
1290 FROB (dim);
1291 FROB (reverse);
1292 FROB (blinking);
1293 /* And do ASCII, of course. */
1294 {
1295 int offs = LEADING_BYTE_ASCII - MIN_LEADING_BYTE;
1296
1297 if (!cachel->font_specified[offs] && FINDEX_FIELD (font_specified[offs]))
1298 {
1299 cachel->font[offs] = FINDEX_FIELD (font[offs]);
1300 cachel->font_specified[offs] = 1;
1301 cachel->dirty = 1;
1302 }
1303 }
1304
1305 #undef FROB
1306 #undef FINDEX_FIELD
1307
1308 cachel->updated = 1;
1309 }
1310
1311 /* Initialize a cachel. */
1312
1313 void
1314 reset_face_cachel (struct face_cachel *cachel)
1315 {
1316 memset (cachel, 0, sizeof (struct face_cachel));
1317 cachel->face = Qunbound;
1318 cachel->nfaces = 0;
1319 cachel->merged_faces = 0;
1320 cachel->foreground = Qunbound;
1321 cachel->background = Qunbound;
1322 {
1323 int i;
1324
1325 for (i = 0; i < NUM_LEADING_BYTES; i++)
1326 cachel->font[i] = Qunbound;
1327 }
1328 cachel->display_table = Qunbound;
1329 cachel->background_pixmap = Qunbound;
1330 }
1331
1332 /* Add a cachel for the given face to the given window's cache. */
1333
1334 static void
1335 add_face_cachel (struct window *w, Lisp_Object face)
1336 {
1337 struct face_cachel new_cachel;
1338 Lisp_Object window;
1339
1340 reset_face_cachel (&new_cachel);
1341 XSETWINDOW (window, w);
1342 update_face_cachel_data (&new_cachel, window, face);
1343 Dynarr_add (w->face_cachels, new_cachel);
1344 }
1345
1346 /* Retrieve the index to a cachel for window W that corresponds to
1347 the specified face. If necessary, add a new element to the
1348 cache. */
1349
1350 face_index
1351 get_builtin_face_cache_index (struct window *w, Lisp_Object face)
1352 {
1353 int elt;
1354
1355 if (noninteractive)
1356 return 0;
1357
1358 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++)
1359 {
1360 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, elt);
1361
1362 if (EQ (cachel->face, face))
1363 {
1364 Lisp_Object window = Qnil;
1365 XSETWINDOW (window, w);
1366 if (!cachel->updated)
1367 update_face_cachel_data (cachel, window, face);
1368 return elt;
1369 }
1370 }
1371
1372 /* If we didn't find the face, add it and then return its index. */
1373 add_face_cachel (w, face);
1374 return elt;
1375 }
1376
1377 void
1378 reset_face_cachels (struct window *w)
1379 {
1380 /* #### Not initialized in batch mode for the stream device. */
1381 if (w->face_cachels)
1382 {
1383 int i;
1384
1385 for (i = 0; i < Dynarr_length (w->face_cachels); i++)
1386 {
1387 struct face_cachel *cachel = Dynarr_atp (w->face_cachels, i);
1388 if (cachel->merged_faces)
1389 Dynarr_free (cachel->merged_faces);
1390 }
1391 Dynarr_reset (w->face_cachels);
1392 get_builtin_face_cache_index (w, Vdefault_face);
1393 get_builtin_face_cache_index (w, Vmodeline_face);
1394 XFRAME (w->frame)->window_face_cache_reset = 1;
1395 }
1396 }
1397
1398 void
1399 mark_face_cachels_as_clean (struct window *w)
1400 {
1401 int elt;
1402
1403 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++)
1404 Dynarr_atp (w->face_cachels, elt)->dirty = 0;
1405 }
1406
1407 void
1408 mark_face_cachels_as_not_updated (struct window *w)
1409 {
1410 int elt;
1411
1412 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++)
1413 {
1414 struct face_cachel *cachel = Dynarr_atp (w->face_cachels, elt);
1415 int i;
1416
1417 cachel->updated = 0;
1418 for (i = 0; i < NUM_LEADING_BYTES; i++)
1419 cachel->font_updated[i] = 0;
1420 }
1421 }
1422
1423 #ifdef MEMORY_USAGE_STATS
1424
1425 int
1426 compute_face_cachel_usage (face_cachel_dynarr *face_cachels,
1427 struct overhead_stats *ovstats)
1428 {
1429 int total = 0;
1430
1431 if (face_cachels)
1432 {
1433 int i;
1434
1435 total += Dynarr_memory_usage (face_cachels, ovstats);
1436 for (i = 0; i < Dynarr_length (face_cachels); i++)
1437 {
1438 int_dynarr *merged = Dynarr_at (face_cachels, i).merged_faces;
1439 if (merged)
1440 total += Dynarr_memory_usage (merged, ovstats);
1441 }
1442 }
1443
1444 return total;
1445 }
1446
1447 #endif /* MEMORY_USAGE_STATS */
1448
1449
1450 /*****************************************************************************
1451 * merged face functions *
1452 *****************************************************************************/
1453
1454 /* Compare two merged face cachels to determine whether we have to add
1455 a new entry to the face cache.
1456
1457 Note that we do not compare the attributes, but just the faces the
1458 cachels are based on. If they are the same, then the cachels certainly
1459 ought to have the same attributes, except in the case where fonts
1460 for different charsets have been determined in the two -- and in that
1461 case this difference is fine. */
1462
1463 static int
1464 compare_merged_face_cachels (struct face_cachel *cachel1,
1465 struct face_cachel *cachel2)
1466 {
1467 int i;
1468
1469 if (!EQ (cachel1->face, cachel2->face)
1470 || cachel1->nfaces != cachel2->nfaces)
1471 return 0;
1472
1473 for (i = 0; i < cachel1->nfaces; i++)
1474 if (FACE_CACHEL_FINDEX_UNSAFE (cachel1, i)
1475 != FACE_CACHEL_FINDEX_UNSAFE (cachel2, i))
1476 return 0;
1477
1478 return 1;
1479 }
1480
1481 /* Retrieve the index to a cachel for window W that corresponds to
1482 the specified cachel. If necessary, add a new element to the
1483 cache. This is similar to get_builtin_face_cache_index() but
1484 is intended for merged cachels rather than for cachels representing
1485 just a face.
1486
1487 Note that a merged cachel for just one face is not the same as
1488 the simple cachel for that face, because it is also merged with
1489 the default face. */
1490
1491 static face_index
1492 get_merged_face_cache_index (struct window *w,
1493 struct face_cachel *merged_cachel)
1494 {
1495 int elt;
1496 int cache_size = Dynarr_length (w->face_cachels);
1497
1498 for (elt = 0; elt < cache_size; elt++)
1499 {
1500 struct face_cachel *cachel =
1501 Dynarr_atp (w->face_cachels, elt);
1502
1503 if (compare_merged_face_cachels (cachel, merged_cachel))
1504 return elt;
1505 }
1506
1507 /* We didn't find it so add this instance to the cache. */
1508 merged_cachel->updated = 1;
1509 merged_cachel->dirty = 1;
1510 Dynarr_add (w->face_cachels, *merged_cachel);
1511 return cache_size;
1512 }
1513
1514 face_index
1515 get_extent_fragment_face_cache_index (struct window *w,
1516 struct extent_fragment *ef)
1517 {
1518 struct face_cachel cachel;
1519 int len = Dynarr_length (ef->extents);
1520 face_index findex;
1521 Lisp_Object window = Qnil;
1522 XSETWINDOW (window, w);
1523
1524 /* Optimize the default case. */
1525 if (len == 0)
1526 return DEFAULT_INDEX;
1527 else
1528 {
1529 int i;
1530
1531 /* Merge the faces of the extents together in order. */
1532
1533 reset_face_cachel (&cachel);
1534
1535 for (i = len - 1; i >= 0; i--)
1536 {
1537 EXTENT current = Dynarr_at (ef->extents, i);
1538 int has_findex = 0;
1539 Lisp_Object face = extent_face (current);
1540
1541 if (FACEP (face))
1542 {
1543 findex = get_builtin_face_cache_index (w, face);
1544 has_findex = 1;
1545 merge_face_cachel_data (w, findex, &cachel);
1546 }
1547 /* remember, we're called from within redisplay
1548 so we can't error. */
1549 else while (CONSP (face))
1550 {
1551 Lisp_Object one_face = XCAR (face);
1552 if (FACEP (one_face))
1553 {
1554 findex = get_builtin_face_cache_index (w, one_face);
1555 merge_face_cachel_data (w, findex, &cachel);
1556
1557 /* code duplication here but there's no clean
1558 way to avoid it. */
1559 if (cachel.nfaces >= NUM_STATIC_CACHEL_FACES)
1560 {
1561 if (!cachel.merged_faces)
1562 cachel.merged_faces = Dynarr_new (int);
1563 Dynarr_add (cachel.merged_faces, findex);
1564 }
1565 else
1566 cachel.merged_faces_static[cachel.nfaces] = findex;
1567 cachel.nfaces++;
1568 }
1569 face = XCDR (face);
1570 }
1571
1572 if (has_findex)
1573 {
1574 if (cachel.nfaces >= NUM_STATIC_CACHEL_FACES)
1575 {
1576 if (!cachel.merged_faces)
1577 cachel.merged_faces = Dynarr_new (int);
1578 Dynarr_add (cachel.merged_faces, findex);
1579 }
1580 else
1581 cachel.merged_faces_static[cachel.nfaces] = findex;
1582 cachel.nfaces++;
1583 }
1584 }
1585
1586 /* Now finally merge in the default face. */
1587 findex = get_builtin_face_cache_index (w, Vdefault_face);
1588 merge_face_cachel_data (w, findex, &cachel);
1589
1590 return get_merged_face_cache_index (w, &cachel);
1591 }
1592 }
1593
1594
1595 /*****************************************************************************
1596 interface functions
1597 ****************************************************************************/
1598
1599 /* #### This function should be converted into appropriate device methods. */
1600 static void
1601 update_EmacsFrame (Lisp_Object frame, Lisp_Object name)
1602 {
1603 struct frame *frm = XFRAME (frame);
1604
1605 #ifdef HAVE_X_WINDOWS
1606 if (FRAME_X_P (frm))
1607 {
1608 Arg av[10];
1609 int ac = 0;
1610
1611 if (EQ (name, Qforeground))
1612 {
1613 Lisp_Object color = FACE_FOREGROUND (Vdefault_face, frame);
1614 XColor fgc;
1615
1616 if (!EQ (color, Vthe_null_color_instance))
1617 {
1618 fgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
1619 XtSetArg (av[ac], XtNforeground, (void *) fgc.pixel); ac++;
1620 }
1621 }
1622 else if (EQ (name, Qbackground))
1623 {
1624 Lisp_Object color = FACE_BACKGROUND (Vdefault_face, frame);
1625 XColor bgc;
1626
1627 if (!EQ (color, Vthe_null_color_instance))
1628 {
1629 bgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
1630 XtSetArg (av[ac], XtNbackground, (void *) bgc.pixel); ac++;
1631 }
1632
1633 /* Really crappy way to force the modeline shadows to be
1634 redrawn. But effective. */
1635 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (frm);
1636 MARK_FRAME_CHANGED (frm);
1637 }
1638 else if (EQ (name, Qfont))
1639 {
1640 Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
1641
1642 if (!EQ (font, Vthe_null_font_instance))
1643 XtSetArg (av[ac], XtNfont,
1644 (void *) FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
1645 ac++;
1646 }
1647 else
1648 abort ();
1649
1650 XtSetValues (FRAME_X_TEXT_WIDGET (frm), av, ac);
1651
1652 #ifdef HAVE_TOOLBARS
1653 /* Setting the background clears the entire frame area
1654 including the toolbar so we force an immediate redraw of
1655 it. */
1656 if (EQ (name, Qbackground))
1657 MAYBE_DEVMETH (XDEVICE (frm->device), redraw_frame_toolbars, (frm));
1658 #endif
1659
1660 /* The intent of this code is to cause the frame size in
1661 characters to remain the same when the font changes, at the
1662 expense of changing the frame size in pixels. It's not
1663 totally clear that this is the right thing to do, but it's
1664 not clearly wrong either. */
1665 if (EQ (name, Qfont))
1666 {
1667 EmacsFrameRecomputeCellSize (FRAME_X_TEXT_WIDGET (frm));
1668 Fset_frame_size (frame,
1669 make_int (frm->width),
1670 make_int (frm->height),
1671 Qnil);
1672 }
1673 }
1674 #endif /* HAVE_X_WINDOWS */
1675
1676 #ifdef HAVE_NEXTSTEP
1677 if (FRAME_NS_P (frm))
1678 {
1679 /* This code still needs to be written */
1680 }
1681 #endif /* HAVE_NEXSTEP */
1682 }
1683
1684 static void
1685 update_EmacsFrames (Lisp_Object locale, Lisp_Object name)
1686 {
1687 if (FRAMEP (locale))
1688 {
1689 update_EmacsFrame (locale, name);
1690 }
1691 else if (DEVICEP (locale))
1692 {
1693 Lisp_Object frmcons;
1694
1695 DEVICE_FRAME_LOOP (frmcons, XDEVICE (locale))
1696 update_EmacsFrame (XCAR (frmcons), name);
1697 }
1698 else if (EQ (locale, Qglobal) || EQ (locale, Qfallback))
1699 {
1700 Lisp_Object frmcons, devcons, concons;
1701
1702 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1703 update_EmacsFrame (XCAR (frmcons), name);
1704 }
1705 }
1706
1707 void
1708 update_frame_face_values (struct frame *f)
1709 {
1710 Lisp_Object frm = Qnil;
1711
1712 XSETFRAME (frm, f);
1713 update_EmacsFrame (frm, Qforeground);
1714 update_EmacsFrame (frm, Qbackground);
1715 update_EmacsFrame (frm, Qfont);
1716 }
1717
1718 void
1719 face_property_was_changed (Lisp_Object face, Lisp_Object property,
1720 Lisp_Object locale)
1721 {
1722 int default_face = EQ (face, Vdefault_face);
1723
1724 /* If the locale could affect the frame value, then call
1725 update_EmacsFrames just in case. */
1726 if (default_face &&
1727 (EQ (property, Qforeground) ||
1728 EQ (property, Qbackground) ||
1729 EQ (property, Qfont)))
1730 update_EmacsFrames (locale, property);
1731
1732 if (WINDOWP (locale))
1733 {
1734 MARK_FRAME_FACES_CHANGED (XFRAME (XWINDOW (locale)->frame));
1735 }
1736 else if (FRAMEP (locale))
1737 {
1738 MARK_FRAME_FACES_CHANGED (XFRAME (locale));
1739 }
1740 else if (DEVICEP (locale))
1741 {
1742 MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (locale));
1743 }
1744 else
1745 {
1746 Lisp_Object devcons, concons;
1747
1748 DEVICE_LOOP_NO_BREAK (devcons, concons)
1749 MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (XCAR (devcons)));
1750 }
1751
1752 update_faces_inheritance (face, property);
1753 XFACE (face)->dirty = 1;
1754 }
1755
1756 DEFUN ("copy-face", Fcopy_face, Scopy_face, 2, 6, 0 /*
1757 Defines and returns a new face which is a copy of an existing one,
1758 or makes an already-existing face be exactly like another. LOCALE,
1759 TAG-SET, EXACT-P, and HOW-TO-ADD are as in `copy-specifier'.
1760 */ )
1761 (old_face, new_name, locale, tag_set, exact_p, how_to_add)
1762 Lisp_Object old_face, new_name, locale, tag_set, exact_p, how_to_add;
1763 {
1764 struct Lisp_Face *fold, *fnew;
1765 Lisp_Object new_face = Qnil;
1766 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1767
1768 old_face = Fget_face (old_face);
1769
1770 /* We GCPRO old_face because it might be temporary, and GCing could
1771 occur in various places below. */
1772 GCPRO4 (tag_set, locale, old_face, new_face);
1773 /* check validity of how_to_add now. */
1774 (void) decode_how_to_add_specification (how_to_add);
1775 /* and of tag_set. */
1776 tag_set = decode_specifier_tag_set (tag_set);
1777 /* and of locale. */
1778 locale = decode_locale_list (locale);
1779
1780 new_face = Ffind_face (new_name);
1781 if (NILP (new_face))
1782 {
1783 Lisp_Object temp;
1784
1785 CHECK_SYMBOL (new_name);
1786
1787 /* Create the new face with the same status as the old face. */
1788 temp = (NILP (Fgethash (old_face, Vtemporary_faces_cache, Qnil))
1789 ? Qnil
1790 : Qt);
1791
1792 new_face = Fmake_face (new_name, Qnil, temp);
1793 }
1794
1795 fold = XFACE (old_face);
1796 fnew = XFACE (new_face);
1797
1798 Fcopy_specifier (fold->foreground, fnew->foreground, locale,
1799 tag_set, exact_p, how_to_add);
1800 Fcopy_specifier (fold->background, fnew->background, locale,
1801 tag_set, exact_p, how_to_add);
1802 Fcopy_specifier (fold->font, fnew->font, locale,
1803 tag_set, exact_p, how_to_add);
1804 Fcopy_specifier (fold->display_table, fnew->display_table, locale,
1805 tag_set, exact_p, how_to_add);
1806 Fcopy_specifier (fold->background_pixmap, fnew->background_pixmap,
1807 locale, tag_set, exact_p, how_to_add);
1808 Fcopy_specifier (fold->underline, fnew->underline, locale,
1809 tag_set, exact_p, how_to_add);
1810 Fcopy_specifier (fold->strikethru, fnew->strikethru, locale,
1811 tag_set, exact_p, how_to_add);
1812 Fcopy_specifier (fold->highlight, fnew->highlight, locale,
1813 tag_set, exact_p, how_to_add);
1814 Fcopy_specifier (fold->dim, fnew->dim, locale,
1815 tag_set, exact_p, how_to_add);
1816 Fcopy_specifier (fold->blinking, fnew->blinking, locale,
1817 tag_set, exact_p, how_to_add);
1818 Fcopy_specifier (fold->reverse, fnew->reverse, locale,
1819 tag_set, exact_p, how_to_add);
1820 /* #### should it copy the individual specifiers, if they exist? */
1821 fnew->plist = Fcopy_sequence (fold->plist);
1822
1823 UNGCPRO;
1824
1825 return new_name;
1826 }
1827
1828
1829 void
1830 syms_of_faces (void)
1831 {
1832 /* Qdefault defined in general.c */
1833 defsymbol (&Qmodeline, "modeline");
1834 defsymbol (&Qleft_margin, "left-margin");
1835 defsymbol (&Qright_margin, "right-margin");
1836 defsymbol (&Qtext_cursor, "text-cursor");
1837
1838 defsubr (&Sfacep);
1839 defsubr (&Sfind_face);
1840 defsubr (&Sget_face);
1841 defsubr (&Sface_name);
1842 defsubr (&Sbuilt_in_face_specifiers);
1843 defsubr (&Sface_list);
1844 defsubr (&Smake_face);
1845 defsubr (&Scopy_face);
1846
1847 defsymbol (&Qfacep, "facep");
1848 defsymbol (&Qforeground, "foreground");
1849 defsymbol (&Qbackground, "background");
1850 /* Qfont defined in general.c */
1851 defsymbol (&Qdisplay_table, "display-table");
1852 defsymbol (&Qbackground_pixmap, "background-pixmap");
1853 defsymbol (&Qunderline, "underline");
1854 defsymbol (&Qstrikethru, "strikethru");
1855 /* Qhighlight, Qreverse defined in general.c */
1856 defsymbol (&Qdim, "dim");
1857 defsymbol (&Qblinking, "blinking");
1858
1859 defsymbol (&Qinit_face_from_resources, "init-face-from-resources");
1860 defsymbol (&Qinit_global_faces, "init-global-faces");
1861 defsymbol (&Qinit_device_faces, "init-device-faces");
1862 defsymbol (&Qinit_frame_faces, "init-frame-faces");
1863 }
1864
1865 void
1866 structure_type_create_faces (void)
1867 {
1868 struct structure_type *st;
1869
1870 st = define_structure_type (Qface, face_validate, face_instantiate);
1871
1872 define_structure_type_keyword (st, Qname, face_name_validate);
1873 }
1874
1875 void
1876 vars_of_faces (void)
1877 {
1878 staticpro (&Vpermanent_faces_cache);
1879 Vpermanent_faces_cache = Qnil;
1880 staticpro (&Vtemporary_faces_cache);
1881 Vtemporary_faces_cache = Qnil;
1882
1883 staticpro (&Vdefault_face);
1884 Vdefault_face = Qnil;
1885 staticpro (&Vmodeline_face);
1886 Vmodeline_face = Qnil;
1887
1888 staticpro (&Vleft_margin_face);
1889 Vleft_margin_face = Qnil;
1890 staticpro (&Vright_margin_face);
1891 Vright_margin_face = Qnil;
1892 staticpro (&Vtext_cursor_face);
1893 Vtext_cursor_face = Qnil;
1894 staticpro (&Vpointer_face);
1895 Vpointer_face = Qnil;
1896
1897 {
1898 Lisp_Object syms[20];
1899 int n = 0;
1900
1901 syms[n++] = Qforeground;
1902 syms[n++] = Qbackground;
1903 syms[n++] = Qfont;
1904 syms[n++] = Qdisplay_table;
1905 syms[n++] = Qbackground_pixmap;
1906 syms[n++] = Qunderline;
1907 syms[n++] = Qstrikethru;
1908 syms[n++] = Qhighlight;
1909 syms[n++] = Qdim;
1910 syms[n++] = Qblinking;
1911 syms[n++] = Qreverse;
1912
1913 Vbuilt_in_face_specifiers = pure_list (n, syms);
1914 staticpro (&Vbuilt_in_face_specifiers);
1915 }
1916 }
1917
1918 void
1919 complex_vars_of_faces (void)
1920 {
1921 Vpermanent_faces_cache = make_lisp_hashtable (10, HASHTABLE_NONWEAK,
1922 HASHTABLE_EQ);
1923 Vtemporary_faces_cache = make_lisp_hashtable (0, HASHTABLE_WEAK,
1924 HASHTABLE_EQ);
1925
1926 /* Create the default face now so we know what it is immediately. */
1927
1928 Vdefault_face = Qnil; /* so that Fmake_face() doesn't set up a bogus
1929 default value */
1930 Vdefault_face = Fmake_face (Qdefault, build_string ("default face"),
1931 Qnil);
1932
1933 /* Provide some last-resort fallbacks to avoid utter fuckage if
1934 someone provides invalid values for the global specifications. */
1935
1936 {
1937 Lisp_Object fg_inst_list = Qnil, bg_inst_list = Qnil;
1938
1939 #ifdef HAVE_X_WINDOWS
1940 fg_inst_list = Fcons (Fcons (list1 (Qx), build_string ("black")),
1941 fg_inst_list);
1942 bg_inst_list = Fcons (Fcons (list1 (Qx), build_string ("white")),
1943 bg_inst_list);
1944 #endif
1945 #ifdef HAVE_TTY
1946 fg_inst_list = Fcons (Fcons (list1 (Qtty), Fvector (0, 0)),
1947 fg_inst_list);
1948 bg_inst_list = Fcons (Fcons (list1 (Qtty), Fvector (0, 0)),
1949 bg_inst_list);
1950 #endif
1951 set_specifier_fallback (Fget (Vdefault_face, Qforeground, Qnil),
1952 fg_inst_list);
1953 set_specifier_fallback (Fget (Vdefault_face, Qbackground, Qnil),
1954 bg_inst_list);
1955 }
1956
1957 /* #### We may want to have different fallback values if NeXTstep
1958 support is compiled in. */
1959 {
1960 Lisp_Object inst_list = Qnil;
1961 #ifdef HAVE_X_WINDOWS
1962 CONST char *fonts[30];
1963 int n = 0;
1964
1965 /* The same gory list from x-faces.el.
1966 (#### Perhaps we should remove the stuff from x-faces.el
1967 and only depend on this stuff here? That should work.)
1968 */
1969 fonts[n++] = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*";
1970 fonts[n++] = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*";
1971 fonts[n++] = "-*-courier-*-r-*-*-*-120-*-*-*-*-iso8859-*";
1972 fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-m-*-iso8859-*";
1973 fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-c-*-iso8859-*";
1974 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-m-*-iso8859-*";
1975 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-c-*-iso8859-*";
1976 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-*-*-iso8859-*";
1977 fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-m-*-*-*";
1978 fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-c-*-*-*";
1979 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-m-*-*-*";
1980 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-c-*-*-*";
1981 fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-*-*-*-*";
1982 fonts[n++] = "-*-*-*-*-*-*-*-120-*-*-*-*-*-*";
1983 fonts[n++] = "*";
1984
1985 for (--n; n >= 0; --n)
1986 inst_list = Fcons (Fcons (list1 (Qx), build_string (fonts[n])),
1987 inst_list);
1988 #endif
1989 #ifdef HAVE_TTY
1990 inst_list = Fcons (Fcons (list1 (Qtty), build_string ("normal")),
1991 inst_list);
1992 #endif
1993 set_specifier_fallback (Fget (Vdefault_face, Qfont, Qnil), inst_list);
1994 }
1995
1996 set_specifier_fallback (Fget (Vdefault_face, Qunderline, Qnil),
1997 list1 (Fcons (Qnil, Qnil)));
1998 set_specifier_fallback (Fget (Vdefault_face, Qstrikethru, Qnil),
1999 list1 (Fcons (Qnil, Qnil)));
2000 set_specifier_fallback (Fget (Vdefault_face, Qhighlight, Qnil),
2001 list1 (Fcons (Qnil, Qnil)));
2002 set_specifier_fallback (Fget (Vdefault_face, Qdim, Qnil),
2003 list1 (Fcons (Qnil, Qnil)));
2004 set_specifier_fallback (Fget (Vdefault_face, Qblinking, Qnil),
2005 list1 (Fcons (Qnil, Qnil)));
2006 set_specifier_fallback (Fget (Vdefault_face, Qreverse, Qnil),
2007 list1 (Fcons (Qnil, Qnil)));
2008
2009 /* Now create the other faces that redisplay needs to refer to
2010 directly. We could create them in Lisp but it's simpler this
2011 way since we need to get them anyway. */
2012 Vmodeline_face = Fmake_face (Qmodeline, build_string ("modeline face"),
2013 Qnil);
2014 Vleft_margin_face = Fmake_face (Qleft_margin,
2015 build_string ("left margin face"),
2016 Qnil);
2017 Vright_margin_face = Fmake_face (Qright_margin,
2018 build_string ("right margin face"),
2019 Qnil);
2020 Vtext_cursor_face = Fmake_face (Qtext_cursor,
2021 build_string ("face for text cursor"),
2022 Qnil);
2023 Vpointer_face =
2024 Fmake_face (Qpointer,
2025 build_string
2026 ("face for foreground/background colors of mouse pointer"),
2027 Qnil);
2028 }