Mercurial > hg > xemacs-beta
annotate src/faces.c @ 5117:3742ea8250b5 ben-lisp-object ben-lisp-object-final-ws-year-2005
Checking in final CVS version of workspace 'ben-lisp-object'
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Sat, 26 Dec 2009 00:20:27 -0600 |
parents | 1e7cc382eb16 |
children | e0db3c197671 |
rev | line source |
---|---|
428 | 1 /* "Face" primitives |
2 Copyright (C) 1994 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Board of Trustees, University of Illinois. | |
793 | 4 Copyright (C) 1995, 1996, 2001, 2002 Ben Wing. |
428 | 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" | |
872 | 33 #include "device-impl.h" |
428 | 34 #include "elhash.h" |
872 | 35 #include "extents-impl.h" /* for extent_face */ |
428 | 36 #include "faces.h" |
872 | 37 #include "frame-impl.h" |
428 | 38 #include "glyphs.h" |
872 | 39 #include "objects-impl.h" |
428 | 40 #include "specifier.h" |
41 #include "window.h" | |
42 | |
43 Lisp_Object Qfacep; | |
44 Lisp_Object Qforeground, Qbackground, Qdisplay_table; | |
45 Lisp_Object Qbackground_pixmap, Qunderline, Qdim; | |
46 Lisp_Object Qblinking, Qstrikethru; | |
47 | |
48 Lisp_Object Qinit_face_from_resources; | |
49 Lisp_Object Qinit_frame_faces; | |
50 Lisp_Object Qinit_device_faces; | |
51 Lisp_Object Qinit_global_faces; | |
52 | |
53 /* These faces are used directly internally. We use these variables | |
54 to be able to reference them directly and save the overhead of | |
55 calling Ffind_face. */ | |
56 Lisp_Object Vdefault_face, Vmodeline_face, Vgui_element_face; | |
57 Lisp_Object Vleft_margin_face, Vright_margin_face, Vtext_cursor_face; | |
58 Lisp_Object Vpointer_face, Vvertical_divider_face, Vtoolbar_face, Vwidget_face; | |
59 | |
440 | 60 /* Qdefault, Qhighlight, Qleft_margin, Qright_margin defined in general.c */ |
61 Lisp_Object Qmodeline, Qgui_element, Qtext_cursor, Qvertical_divider; | |
428 | 62 |
2867 | 63 Lisp_Object Qface_alias, Qcyclic_face_alias; |
2865 | 64 |
428 | 65 /* In the old implementation Vface_list was a list of the face names, |
66 not the faces themselves. We now distinguish between permanent and | |
67 temporary faces. Permanent faces are kept in a regular hash table, | |
68 temporary faces in a weak hash table. */ | |
69 Lisp_Object Vpermanent_faces_cache; | |
70 Lisp_Object Vtemporary_faces_cache; | |
71 | |
72 Lisp_Object Vbuilt_in_face_specifiers; | |
73 | |
74 | |
75 | |
76 static Lisp_Object | |
77 mark_face (Lisp_Object obj) | |
78 { | |
440 | 79 Lisp_Face *face = XFACE (obj); |
428 | 80 |
81 mark_object (face->name); | |
82 mark_object (face->doc_string); | |
83 | |
84 mark_object (face->foreground); | |
85 mark_object (face->background); | |
86 mark_object (face->font); | |
87 mark_object (face->display_table); | |
88 mark_object (face->background_pixmap); | |
89 mark_object (face->underline); | |
90 mark_object (face->strikethru); | |
91 mark_object (face->highlight); | |
92 mark_object (face->dim); | |
93 mark_object (face->blinking); | |
94 mark_object (face->reverse); | |
95 | |
96 mark_object (face->charsets_warned_about); | |
97 | |
98 return face->plist; | |
99 } | |
100 | |
101 static void | |
2286 | 102 print_face (Lisp_Object obj, Lisp_Object printcharfun, int UNUSED (escapeflag)) |
428 | 103 { |
440 | 104 Lisp_Face *face = XFACE (obj); |
428 | 105 |
106 if (print_readably) | |
107 { | |
800 | 108 write_fmt_string_lisp (printcharfun, "#s(face name %S)", 1, face->name); |
428 | 109 } |
110 else | |
111 { | |
800 | 112 write_fmt_string_lisp (printcharfun, "#<face %S", 1, face->name); |
428 | 113 if (!NILP (face->doc_string)) |
800 | 114 write_fmt_string_lisp (printcharfun, " %S", 1, face->doc_string); |
826 | 115 write_c_string (printcharfun, ">"); |
428 | 116 } |
117 } | |
118 | |
119 /* Faces are equal if all of their display attributes are equal. We | |
120 don't compare names or doc-strings, because that would make equal | |
121 be eq. | |
122 | |
123 This isn't concerned with "unspecified" attributes, that's what | |
124 #'face-differs-from-default-p is for. */ | |
125 static int | |
126 face_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) | |
127 { | |
440 | 128 Lisp_Face *f1 = XFACE (obj1); |
129 Lisp_Face *f2 = XFACE (obj2); | |
428 | 130 |
131 depth++; | |
132 | |
133 return | |
134 (internal_equal (f1->foreground, f2->foreground, depth) && | |
135 internal_equal (f1->background, f2->background, depth) && | |
136 internal_equal (f1->font, f2->font, depth) && | |
137 internal_equal (f1->display_table, f2->display_table, depth) && | |
138 internal_equal (f1->background_pixmap, f2->background_pixmap, depth) && | |
139 internal_equal (f1->underline, f2->underline, depth) && | |
140 internal_equal (f1->strikethru, f2->strikethru, depth) && | |
141 internal_equal (f1->highlight, f2->highlight, depth) && | |
142 internal_equal (f1->dim, f2->dim, depth) && | |
143 internal_equal (f1->blinking, f2->blinking, depth) && | |
144 internal_equal (f1->reverse, f2->reverse, depth) && | |
145 | |
146 ! plists_differ (f1->plist, f2->plist, 0, 0, depth + 1)); | |
147 } | |
148 | |
665 | 149 static Hashcode |
428 | 150 face_hash (Lisp_Object obj, int depth) |
151 { | |
440 | 152 Lisp_Face *f = XFACE (obj); |
428 | 153 |
154 depth++; | |
155 | |
156 /* No need to hash all of the elements; that would take too long. | |
157 Just hash the most common ones. */ | |
158 return HASH3 (internal_hash (f->foreground, depth), | |
159 internal_hash (f->background, depth), | |
160 internal_hash (f->font, depth)); | |
161 } | |
162 | |
163 static Lisp_Object | |
164 face_getprop (Lisp_Object obj, Lisp_Object prop) | |
165 { | |
440 | 166 Lisp_Face *f = XFACE (obj); |
428 | 167 |
168 return | |
169 (EQ (prop, Qforeground) ? f->foreground : | |
170 EQ (prop, Qbackground) ? f->background : | |
171 EQ (prop, Qfont) ? f->font : | |
172 EQ (prop, Qdisplay_table) ? f->display_table : | |
173 EQ (prop, Qbackground_pixmap) ? f->background_pixmap : | |
174 EQ (prop, Qunderline) ? f->underline : | |
175 EQ (prop, Qstrikethru) ? f->strikethru : | |
176 EQ (prop, Qhighlight) ? f->highlight : | |
177 EQ (prop, Qdim) ? f->dim : | |
178 EQ (prop, Qblinking) ? f->blinking : | |
179 EQ (prop, Qreverse) ? f->reverse : | |
180 EQ (prop, Qdoc_string) ? f->doc_string : | |
181 external_plist_get (&f->plist, prop, 0, ERROR_ME)); | |
182 } | |
183 | |
184 static int | |
185 face_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value) | |
186 { | |
440 | 187 Lisp_Face *f = XFACE (obj); |
428 | 188 |
189 if (EQ (prop, Qforeground) || | |
190 EQ (prop, Qbackground) || | |
191 EQ (prop, Qfont) || | |
192 EQ (prop, Qdisplay_table) || | |
193 EQ (prop, Qbackground_pixmap) || | |
194 EQ (prop, Qunderline) || | |
195 EQ (prop, Qstrikethru) || | |
196 EQ (prop, Qhighlight) || | |
197 EQ (prop, Qdim) || | |
198 EQ (prop, Qblinking) || | |
199 EQ (prop, Qreverse)) | |
200 return 0; | |
201 | |
202 if (EQ (prop, Qdoc_string)) | |
203 { | |
204 if (!NILP (value)) | |
205 CHECK_STRING (value); | |
206 f->doc_string = value; | |
207 return 1; | |
208 } | |
209 | |
210 external_plist_put (&f->plist, prop, value, 0, ERROR_ME); | |
211 return 1; | |
212 } | |
213 | |
214 static int | |
215 face_remprop (Lisp_Object obj, Lisp_Object prop) | |
216 { | |
440 | 217 Lisp_Face *f = XFACE (obj); |
428 | 218 |
219 if (EQ (prop, Qforeground) || | |
220 EQ (prop, Qbackground) || | |
221 EQ (prop, Qfont) || | |
222 EQ (prop, Qdisplay_table) || | |
223 EQ (prop, Qbackground_pixmap) || | |
224 EQ (prop, Qunderline) || | |
225 EQ (prop, Qstrikethru) || | |
226 EQ (prop, Qhighlight) || | |
227 EQ (prop, Qdim) || | |
228 EQ (prop, Qblinking) || | |
229 EQ (prop, Qreverse)) | |
230 return -1; | |
231 | |
232 if (EQ (prop, Qdoc_string)) | |
233 { | |
234 f->doc_string = Qnil; | |
235 return 1; | |
236 } | |
237 | |
238 return external_remprop (&f->plist, prop, 0, ERROR_ME); | |
239 } | |
240 | |
241 static Lisp_Object | |
242 face_plist (Lisp_Object obj) | |
243 { | |
440 | 244 Lisp_Face *face = XFACE (obj); |
428 | 245 Lisp_Object result = face->plist; |
246 | |
247 result = cons3 (Qreverse, face->reverse, result); | |
248 result = cons3 (Qblinking, face->blinking, result); | |
249 result = cons3 (Qdim, face->dim, result); | |
250 result = cons3 (Qhighlight, face->highlight, result); | |
251 result = cons3 (Qstrikethru, face->strikethru, result); | |
252 result = cons3 (Qunderline, face->underline, result); | |
253 result = cons3 (Qbackground_pixmap, face->background_pixmap, result); | |
254 result = cons3 (Qdisplay_table, face->display_table, result); | |
255 result = cons3 (Qfont, face->font, result); | |
256 result = cons3 (Qbackground, face->background, result); | |
257 result = cons3 (Qforeground, face->foreground, result); | |
258 | |
259 return result; | |
260 } | |
261 | |
1204 | 262 static const struct memory_description face_description[] = { |
440 | 263 { XD_LISP_OBJECT, offsetof (Lisp_Face, name) }, |
264 { XD_LISP_OBJECT, offsetof (Lisp_Face, doc_string) }, | |
265 { XD_LISP_OBJECT, offsetof (Lisp_Face, foreground) }, | |
266 { XD_LISP_OBJECT, offsetof (Lisp_Face, background) }, | |
267 { XD_LISP_OBJECT, offsetof (Lisp_Face, font) }, | |
268 { XD_LISP_OBJECT, offsetof (Lisp_Face, display_table) }, | |
269 { XD_LISP_OBJECT, offsetof (Lisp_Face, background_pixmap) }, | |
270 { XD_LISP_OBJECT, offsetof (Lisp_Face, underline) }, | |
271 { XD_LISP_OBJECT, offsetof (Lisp_Face, strikethru) }, | |
272 { XD_LISP_OBJECT, offsetof (Lisp_Face, highlight) }, | |
273 { XD_LISP_OBJECT, offsetof (Lisp_Face, dim) }, | |
274 { XD_LISP_OBJECT, offsetof (Lisp_Face, blinking) }, | |
275 { XD_LISP_OBJECT, offsetof (Lisp_Face, reverse) }, | |
276 { XD_LISP_OBJECT, offsetof (Lisp_Face, plist) }, | |
277 { XD_LISP_OBJECT, offsetof (Lisp_Face, charsets_warned_about) }, | |
428 | 278 { XD_END } |
279 }; | |
280 | |
5117
3742ea8250b5
Checking in final CVS version of workspace 'ben-lisp-object'
Ben Wing <ben@xemacs.org>
parents:
3017
diff
changeset
|
281 DEFINE_LISP_OBJECT_WITH_PROPS ("face", face, |
934 | 282 mark_face, print_face, 0, face_equal, |
1204 | 283 face_hash, face_description, |
284 face_getprop, | |
934 | 285 face_putprop, face_remprop, |
286 face_plist, Lisp_Face); | |
428 | 287 |
288 /************************************************************************/ | |
289 /* face read syntax */ | |
290 /************************************************************************/ | |
291 | |
292 static int | |
2286 | 293 face_name_validate (Lisp_Object UNUSED (keyword), Lisp_Object value, |
578 | 294 Error_Behavior errb) |
428 | 295 { |
296 if (ERRB_EQ (errb, ERROR_ME)) | |
297 { | |
298 CHECK_SYMBOL (value); | |
299 return 1; | |
300 } | |
301 | |
302 return SYMBOLP (value); | |
303 } | |
304 | |
305 static int | |
578 | 306 face_validate (Lisp_Object data, Error_Behavior errb) |
428 | 307 { |
308 int name_seen = 0; | |
309 Lisp_Object valw = Qnil; | |
310 | |
311 data = Fcdr (data); /* skip over Qface */ | |
312 while (!NILP (data)) | |
313 { | |
314 Lisp_Object keyw = Fcar (data); | |
315 | |
316 data = Fcdr (data); | |
317 valw = Fcar (data); | |
318 data = Fcdr (data); | |
319 if (EQ (keyw, Qname)) | |
320 name_seen = 1; | |
321 else | |
2500 | 322 ABORT (); |
428 | 323 } |
324 | |
325 if (!name_seen) | |
326 { | |
563 | 327 maybe_sferror ("No face name given", Qunbound, Qface, errb); |
428 | 328 return 0; |
329 } | |
330 | |
331 if (NILP (Ffind_face (valw))) | |
332 { | |
563 | 333 maybe_invalid_argument ("No such face", valw, Qface, errb); |
428 | 334 return 0; |
335 } | |
336 | |
337 return 1; | |
338 } | |
339 | |
340 static Lisp_Object | |
341 face_instantiate (Lisp_Object data) | |
342 { | |
343 return Fget_face (Fcar (Fcdr (data))); | |
344 } | |
345 | |
346 | |
347 /**************************************************************************** | |
348 * utility functions * | |
349 ****************************************************************************/ | |
350 | |
351 static void | |
440 | 352 reset_face (Lisp_Face *f) |
428 | 353 { |
354 f->name = Qnil; | |
355 f->doc_string = Qnil; | |
356 f->dirty = 0; | |
357 f->foreground = Qnil; | |
358 f->background = Qnil; | |
359 f->font = Qnil; | |
360 f->display_table = Qnil; | |
361 f->background_pixmap = Qnil; | |
362 f->underline = Qnil; | |
363 f->strikethru = Qnil; | |
364 f->highlight = Qnil; | |
365 f->dim = Qnil; | |
366 f->blinking = Qnil; | |
367 f->reverse = Qnil; | |
368 f->plist = Qnil; | |
369 f->charsets_warned_about = Qnil; | |
370 } | |
371 | |
440 | 372 static Lisp_Face * |
428 | 373 allocate_face (void) |
374 { | |
5117
3742ea8250b5
Checking in final CVS version of workspace 'ben-lisp-object'
Ben Wing <ben@xemacs.org>
parents:
3017
diff
changeset
|
375 Lisp_Object obj = ALLOC_LISP_OBJECT (face); |
3742ea8250b5
Checking in final CVS version of workspace 'ben-lisp-object'
Ben Wing <ben@xemacs.org>
parents:
3017
diff
changeset
|
376 Lisp_Face *result = XFACE (obj); |
428 | 377 |
378 reset_face (result); | |
379 return result; | |
380 } | |
381 | |
382 | |
383 /* We store the faces in hash tables with the names as the key and the | |
384 actual face object as the value. Occasionally we need to use them | |
385 in a list format. These routines provide us with that. */ | |
386 struct face_list_closure | |
387 { | |
388 Lisp_Object *face_list; | |
389 }; | |
390 | |
391 static int | |
2286 | 392 add_face_to_list_mapper (Lisp_Object UNUSED (key), Lisp_Object value, |
428 | 393 void *face_list_closure) |
394 { | |
395 /* This function can GC */ | |
396 struct face_list_closure *fcl = | |
397 (struct face_list_closure *) face_list_closure; | |
398 | |
399 *(fcl->face_list) = Fcons (XFACE (value)->name, (*fcl->face_list)); | |
400 return 0; | |
401 } | |
402 | |
403 static Lisp_Object | |
404 faces_list_internal (Lisp_Object list) | |
405 { | |
406 Lisp_Object face_list = Qnil; | |
407 struct gcpro gcpro1; | |
408 struct face_list_closure face_list_closure; | |
409 | |
410 GCPRO1 (face_list); | |
411 face_list_closure.face_list = &face_list; | |
412 elisp_maphash (add_face_to_list_mapper, list, &face_list_closure); | |
413 UNGCPRO; | |
414 | |
415 return face_list; | |
416 } | |
417 | |
418 static Lisp_Object | |
419 permanent_faces_list (void) | |
420 { | |
421 return faces_list_internal (Vpermanent_faces_cache); | |
422 } | |
423 | |
424 static Lisp_Object | |
425 temporary_faces_list (void) | |
426 { | |
427 return faces_list_internal (Vtemporary_faces_cache); | |
428 } | |
429 | |
430 | |
431 static int | |
2286 | 432 mark_face_as_clean_mapper (Lisp_Object UNUSED (key), Lisp_Object value, |
428 | 433 void *flag_closure) |
434 { | |
435 /* This function can GC */ | |
436 int *flag = (int *) flag_closure; | |
437 XFACE (value)->dirty = *flag; | |
438 return 0; | |
439 } | |
440 | |
441 static void | |
442 mark_all_faces_internal (int flag) | |
443 { | |
444 elisp_maphash (mark_face_as_clean_mapper, Vpermanent_faces_cache, &flag); | |
445 elisp_maphash (mark_face_as_clean_mapper, Vtemporary_faces_cache, &flag); | |
446 } | |
447 | |
448 void | |
449 mark_all_faces_as_clean (void) | |
450 { | |
451 mark_all_faces_internal (0); | |
452 } | |
453 | |
454 /* Currently unused (see the comment in face_property_was_changed()). */ | |
455 #if 0 | |
456 /* #### OBSOLETE ME, PLEASE. Maybe. Maybe this is just as good as | |
457 any other solution. */ | |
458 struct face_inheritance_closure | |
459 { | |
460 Lisp_Object face; | |
461 Lisp_Object property; | |
462 }; | |
463 | |
464 static void | |
465 update_inheritance_mapper_internal (Lisp_Object cur_face, | |
466 Lisp_Object inh_face, | |
467 Lisp_Object property) | |
468 { | |
469 /* #### fix this function */ | |
470 Lisp_Object elt = Qnil; | |
471 struct gcpro gcpro1; | |
472 | |
473 GCPRO1 (elt); | |
474 | |
475 for (elt = FACE_PROPERTY_SPEC_LIST (cur_face, property, Qall); | |
476 !NILP (elt); | |
477 elt = XCDR (elt)) | |
478 { | |
479 Lisp_Object values = XCDR (XCAR (elt)); | |
480 | |
481 for (; !NILP (values); values = XCDR (values)) | |
482 { | |
483 Lisp_Object value = XCDR (XCAR (values)); | |
484 if (VECTORP (value) && XVECTOR_LENGTH (value)) | |
485 { | |
486 if (EQ (Ffind_face (XVECTOR_DATA (value)[0]), inh_face)) | |
487 Fset_specifier_dirty_flag | |
488 (FACE_PROPERTY_SPECIFIER (inh_face, property)); | |
489 } | |
490 } | |
491 } | |
492 | |
493 UNGCPRO; | |
494 } | |
495 | |
496 static int | |
442 | 497 update_face_inheritance_mapper (const void *hash_key, void *hash_contents, |
428 | 498 void *face_inheritance_closure) |
499 { | |
500 Lisp_Object key, contents; | |
501 struct face_inheritance_closure *fcl = | |
502 (struct face_inheritance_closure *) face_inheritance_closure; | |
503 | |
826 | 504 key = VOID_TO_LISP (hash_key); |
505 contents = VOID_TO_LISP (hash_contents); | |
428 | 506 |
507 if (EQ (fcl->property, Qfont)) | |
508 { | |
509 update_inheritance_mapper_internal (contents, fcl->face, Qfont); | |
510 } | |
511 else if (EQ (fcl->property, Qforeground) || | |
512 EQ (fcl->property, Qbackground)) | |
513 { | |
514 update_inheritance_mapper_internal (contents, fcl->face, Qforeground); | |
515 update_inheritance_mapper_internal (contents, fcl->face, Qbackground); | |
516 } | |
517 else if (EQ (fcl->property, Qunderline) || | |
518 EQ (fcl->property, Qstrikethru) || | |
519 EQ (fcl->property, Qhighlight) || | |
520 EQ (fcl->property, Qdim) || | |
521 EQ (fcl->property, Qblinking) || | |
522 EQ (fcl->property, Qreverse)) | |
523 { | |
524 update_inheritance_mapper_internal (contents, fcl->face, Qunderline); | |
525 update_inheritance_mapper_internal (contents, fcl->face, Qstrikethru); | |
526 update_inheritance_mapper_internal (contents, fcl->face, Qhighlight); | |
527 update_inheritance_mapper_internal (contents, fcl->face, Qdim); | |
528 update_inheritance_mapper_internal (contents, fcl->face, Qblinking); | |
529 update_inheritance_mapper_internal (contents, fcl->face, Qreverse); | |
530 } | |
531 return 0; | |
532 } | |
533 | |
534 static void | |
535 update_faces_inheritance (Lisp_Object face, Lisp_Object property) | |
536 { | |
537 struct face_inheritance_closure face_inheritance_closure; | |
538 struct gcpro gcpro1, gcpro2; | |
539 | |
540 GCPRO2 (face, property); | |
541 face_inheritance_closure.face = face; | |
542 face_inheritance_closure.property = property; | |
543 | |
544 elisp_maphash (update_face_inheritance_mapper, Vpermanent_faces_cache, | |
545 &face_inheritance_closure); | |
546 elisp_maphash (update_face_inheritance_mapper, Vtemporary_faces_cache, | |
547 &face_inheritance_closure); | |
548 | |
549 UNGCPRO; | |
550 } | |
551 #endif /* 0 */ | |
552 | |
553 Lisp_Object | |
554 face_property_matching_instance (Lisp_Object face, Lisp_Object property, | |
555 Lisp_Object charset, Lisp_Object domain, | |
578 | 556 Error_Behavior errb, int no_fallback, |
428 | 557 Lisp_Object depth) |
558 { | |
771 | 559 Lisp_Object retval; |
872 | 560 Lisp_Object matchspec = Qunbound; |
561 struct gcpro gcpro1; | |
771 | 562 |
872 | 563 if (!NILP (charset)) |
564 matchspec = noseeum_cons (charset, Qnil); | |
565 GCPRO1 (matchspec); | |
566 retval = specifier_instance_no_quit (Fget (face, property, Qnil), matchspec, | |
771 | 567 domain, errb, no_fallback, depth); |
872 | 568 if (UNBOUNDP (retval)) |
569 { | |
874 | 570 if (CONSP (matchspec)) |
571 Fsetcdr (matchspec, Qt); | |
872 | 572 retval = specifier_instance_no_quit (Fget (face, property, Qnil), |
573 matchspec, domain, errb, | |
574 no_fallback, depth); | |
575 } | |
576 UNGCPRO; | |
577 if (CONSP (matchspec)) | |
578 free_cons (matchspec); | |
428 | 579 |
580 if (UNBOUNDP (retval) && !no_fallback) | |
581 { | |
582 if (EQ (property, Qfont)) | |
583 { | |
584 if (NILP (memq_no_quit (charset, | |
585 XFACE (face)->charsets_warned_about))) | |
586 { | |
587 #ifdef MULE | |
793 | 588 if (!UNBOUNDP (charset)) |
428 | 589 warn_when_safe |
793 | 590 (Qfont, Qnotice, |
591 "Unable to instantiate font for charset %s, face %s", | |
592 XSTRING_DATA (symbol_name | |
593 (XSYMBOL (XCHARSET_NAME (charset)))), | |
594 XSTRING_DATA (symbol_name | |
595 (XSYMBOL (XFACE (face)->name)))); | |
428 | 596 else |
597 #endif | |
793 | 598 warn_when_safe (Qfont, Qnotice, |
428 | 599 "Unable to instantiate font for face %s", |
793 | 600 XSTRING_DATA (symbol_name |
428 | 601 (XSYMBOL (XFACE (face)->name)))); |
602 XFACE (face)->charsets_warned_about = | |
603 Fcons (charset, XFACE (face)->charsets_warned_about); | |
604 } | |
605 retval = Vthe_null_font_instance; | |
606 } | |
607 } | |
608 | |
609 return retval; | |
610 } | |
611 | |
612 | |
613 DEFUN ("facep", Ffacep, 1, 1, 0, /* | |
444 | 614 Return t if OBJECT is a face. |
428 | 615 */ |
616 (object)) | |
617 { | |
618 return FACEP (object) ? Qt : Qnil; | |
619 } | |
620 | |
621 DEFUN ("find-face", Ffind_face, 1, 1, 0, /* | |
622 Retrieve the face of the given name. | |
623 If FACE-OR-NAME is a face object, it is simply returned. | |
624 Otherwise, FACE-OR-NAME should be a symbol. If there is no such face, | |
625 nil is returned. Otherwise the associated face object is returned. | |
626 */ | |
627 (face_or_name)) | |
628 { | |
629 Lisp_Object retval; | |
2865 | 630 Lisp_Object face_name; |
631 Lisp_Object face_alias; | |
632 int i; | |
428 | 633 |
634 if (FACEP (face_or_name)) | |
635 return face_or_name; | |
2865 | 636 |
637 face_name = face_or_name; | |
638 CHECK_SYMBOL (face_name); | |
639 | |
2867 | 640 # define FACE_ALIAS_MAX_DEPTH 32 |
2865 | 641 |
642 i = 0; | |
643 while (! NILP ((face_alias = Fget (face_name, Qface_alias, Qnil))) | |
2867 | 644 && i < FACE_ALIAS_MAX_DEPTH) |
2865 | 645 { |
646 face_name = face_alias; | |
647 CHECK_SYMBOL (face_alias); | |
648 i += 1; | |
649 } | |
650 | |
651 /* #### This test actually makes the aliasing max depth to 30, which is more | |
652 #### than enough IMO. -- dvl */ | |
2867 | 653 if (i == FACE_ALIAS_MAX_DEPTH) |
654 signal_error (Qcyclic_face_alias, | |
2865 | 655 "Max face aliasing depth reached", |
656 face_name); | |
657 | |
2867 | 658 # undef FACE_ALIAS_MAX_DEPTH |
428 | 659 |
660 /* Check if the name represents a permanent face. */ | |
2865 | 661 retval = Fgethash (face_name, Vpermanent_faces_cache, Qnil); |
428 | 662 if (!NILP (retval)) |
663 return retval; | |
664 | |
665 /* Check if the name represents a temporary face. */ | |
2865 | 666 return Fgethash (face_name, Vtemporary_faces_cache, Qnil); |
428 | 667 } |
668 | |
669 DEFUN ("get-face", Fget_face, 1, 1, 0, /* | |
670 Retrieve the face of the given name. | |
671 Same as `find-face' except an error is signalled if there is no such | |
672 face instead of returning nil. | |
673 */ | |
674 (name)) | |
675 { | |
676 Lisp_Object face = Ffind_face (name); | |
677 | |
678 if (NILP (face)) | |
563 | 679 invalid_argument ("No such face", name); |
428 | 680 return face; |
681 } | |
682 | |
683 DEFUN ("face-name", Fface_name, 1, 1, 0, /* | |
684 Return the name of the given face. | |
685 */ | |
686 (face)) | |
687 { | |
688 return XFACE (Fget_face (face))->name; | |
689 } | |
690 | |
691 DEFUN ("built-in-face-specifiers", Fbuilt_in_face_specifiers, 0, 0, 0, /* | |
692 Return a list of all built-in face specifier properties. | |
693 Don't modify this list! | |
694 */ | |
695 ()) | |
696 { | |
697 return Vbuilt_in_face_specifiers; | |
698 } | |
699 | |
700 /* These values are retrieved so often that we make a special | |
701 function. | |
702 */ | |
703 | |
704 void | |
705 default_face_font_info (Lisp_Object domain, int *ascent, int *descent, | |
706 int *height, int *width, int *proportional_p) | |
707 { | |
708 Lisp_Object font_instance; | |
709 | |
710 if (noninteractive) | |
711 { | |
712 if (ascent) | |
713 *ascent = 1; | |
714 if (descent) | |
715 *descent = 0; | |
716 if (height) | |
717 *height = 1; | |
718 if (width) | |
719 *width = 1; | |
720 if (proportional_p) | |
721 *proportional_p = 0; | |
722 return; | |
723 } | |
724 | |
725 /* We use ASCII here. This is probably reasonable because the | |
726 people calling this function are using the resulting values to | |
727 come up with overall sizes for windows and frames. */ | |
728 if (WINDOWP (domain)) | |
729 { | |
730 struct face_cachel *cachel; | |
731 struct window *w = XWINDOW (domain); | |
732 | |
733 /* #### It's possible for this function to get called when the | |
734 face cachels have not been initialized. I don't know why. */ | |
735 if (!Dynarr_length (w->face_cachels)) | |
736 reset_face_cachels (w); | |
737 cachel = WINDOW_FACE_CACHEL (w, DEFAULT_INDEX); | |
738 font_instance = FACE_CACHEL_FONT (cachel, Vcharset_ascii); | |
739 } | |
740 else | |
741 { | |
742 font_instance = FACE_FONT (Vdefault_face, domain, Vcharset_ascii); | |
743 } | |
744 | |
745 if (height) | |
746 *height = XFONT_INSTANCE (font_instance)->height; | |
747 if (width) | |
748 *width = XFONT_INSTANCE (font_instance)->width; | |
749 if (ascent) | |
750 *ascent = XFONT_INSTANCE (font_instance)->ascent; | |
751 if (descent) | |
752 *descent = XFONT_INSTANCE (font_instance)->descent; | |
753 if (proportional_p) | |
754 *proportional_p = XFONT_INSTANCE (font_instance)->proportional_p; | |
755 } | |
756 | |
757 void | |
758 default_face_height_and_width (Lisp_Object domain, | |
759 int *height, int *width) | |
760 { | |
761 default_face_font_info (domain, 0, 0, height, width, 0); | |
762 } | |
763 | |
764 void | |
765 default_face_height_and_width_1 (Lisp_Object domain, | |
766 int *height, int *width) | |
767 { | |
768 if (window_system_pixelated_geometry (domain)) | |
769 { | |
770 if (height) | |
771 *height = 1; | |
772 if (width) | |
773 *width = 1; | |
774 } | |
775 else | |
776 default_face_height_and_width (domain, height, width); | |
777 } | |
778 | |
779 DEFUN ("face-list", Fface_list, 0, 1, 0, /* | |
780 Return a list of the names of all defined faces. | |
781 If TEMPORARY is nil, only the permanent faces are included. | |
782 If it is t, only the temporary faces are included. If it is any | |
783 other non-nil value both permanent and temporary are included. | |
784 */ | |
785 (temporary)) | |
786 { | |
787 Lisp_Object face_list = Qnil; | |
788 | |
789 /* Added the permanent faces, if requested. */ | |
790 if (NILP (temporary) || !EQ (Qt, temporary)) | |
791 face_list = permanent_faces_list (); | |
792 | |
793 if (!NILP (temporary)) | |
794 { | |
795 struct gcpro gcpro1; | |
796 GCPRO1 (face_list); | |
797 face_list = nconc2 (face_list, temporary_faces_list ()); | |
798 UNGCPRO; | |
799 } | |
800 | |
801 return face_list; | |
802 } | |
803 | |
804 DEFUN ("make-face", Fmake_face, 1, 3, 0, /* | |
444 | 805 Define a new face with name NAME (a symbol), described by DOC-STRING. |
806 You can modify the font, color, etc. of a face with the set-face-* functions. | |
428 | 807 If the face already exists, it is unmodified. |
808 If TEMPORARY is non-nil, this face will cease to exist if not in use. | |
809 */ | |
810 (name, doc_string, temporary)) | |
811 { | |
812 /* This function can GC if initialized is non-zero */ | |
440 | 813 Lisp_Face *f; |
428 | 814 Lisp_Object face; |
815 | |
816 CHECK_SYMBOL (name); | |
817 if (!NILP (doc_string)) | |
818 CHECK_STRING (doc_string); | |
819 | |
820 face = Ffind_face (name); | |
821 if (!NILP (face)) | |
822 return face; | |
823 | |
824 f = allocate_face (); | |
793 | 825 face = wrap_face (f); |
428 | 826 |
827 f->name = name; | |
828 f->doc_string = doc_string; | |
829 f->foreground = Fmake_specifier (Qcolor); | |
830 set_color_attached_to (f->foreground, face, Qforeground); | |
831 f->background = Fmake_specifier (Qcolor); | |
832 set_color_attached_to (f->background, face, Qbackground); | |
833 f->font = Fmake_specifier (Qfont); | |
834 set_font_attached_to (f->font, face, Qfont); | |
835 f->background_pixmap = Fmake_specifier (Qimage); | |
836 set_image_attached_to (f->background_pixmap, face, Qbackground_pixmap); | |
837 f->display_table = Fmake_specifier (Qdisplay_table); | |
838 f->underline = Fmake_specifier (Qface_boolean); | |
839 set_face_boolean_attached_to (f->underline, face, Qunderline); | |
840 f->strikethru = Fmake_specifier (Qface_boolean); | |
841 set_face_boolean_attached_to (f->strikethru, face, Qstrikethru); | |
842 f->highlight = Fmake_specifier (Qface_boolean); | |
843 set_face_boolean_attached_to (f->highlight, face, Qhighlight); | |
844 f->dim = Fmake_specifier (Qface_boolean); | |
845 set_face_boolean_attached_to (f->dim, face, Qdim); | |
846 f->blinking = Fmake_specifier (Qface_boolean); | |
847 set_face_boolean_attached_to (f->blinking, face, Qblinking); | |
848 f->reverse = Fmake_specifier (Qface_boolean); | |
849 set_face_boolean_attached_to (f->reverse, face, Qreverse); | |
850 if (!NILP (Vdefault_face)) | |
851 { | |
852 /* If the default face has already been created, set it as | |
853 the default fallback specifier for all the specifiers we | |
854 just created. This implements the standard "all faces | |
855 inherit from default" behavior. */ | |
856 set_specifier_fallback (f->foreground, | |
857 Fget (Vdefault_face, Qforeground, Qunbound)); | |
858 set_specifier_fallback (f->background, | |
859 Fget (Vdefault_face, Qbackground, Qunbound)); | |
860 set_specifier_fallback (f->font, | |
861 Fget (Vdefault_face, Qfont, Qunbound)); | |
862 set_specifier_fallback (f->background_pixmap, | |
863 Fget (Vdefault_face, Qbackground_pixmap, | |
864 Qunbound)); | |
865 set_specifier_fallback (f->display_table, | |
866 Fget (Vdefault_face, Qdisplay_table, Qunbound)); | |
867 set_specifier_fallback (f->underline, | |
868 Fget (Vdefault_face, Qunderline, Qunbound)); | |
869 set_specifier_fallback (f->strikethru, | |
870 Fget (Vdefault_face, Qstrikethru, Qunbound)); | |
871 set_specifier_fallback (f->highlight, | |
872 Fget (Vdefault_face, Qhighlight, Qunbound)); | |
873 set_specifier_fallback (f->dim, | |
874 Fget (Vdefault_face, Qdim, Qunbound)); | |
875 set_specifier_fallback (f->blinking, | |
876 Fget (Vdefault_face, Qblinking, Qunbound)); | |
877 set_specifier_fallback (f->reverse, | |
878 Fget (Vdefault_face, Qreverse, Qunbound)); | |
879 } | |
880 | |
881 /* Add the face to the appropriate list. */ | |
882 if (NILP (temporary)) | |
883 Fputhash (name, face, Vpermanent_faces_cache); | |
884 else | |
885 Fputhash (name, face, Vtemporary_faces_cache); | |
886 | |
887 /* Note that it's OK if we dump faces. | |
888 When we start up again when we're not noninteractive, | |
889 `init-global-faces' is called and it resources all | |
890 existing faces. */ | |
891 if (initialized && !noninteractive) | |
892 { | |
893 struct gcpro gcpro1, gcpro2; | |
894 | |
895 GCPRO2 (name, face); | |
896 call1 (Qinit_face_from_resources, name); | |
897 UNGCPRO; | |
898 } | |
899 | |
900 return face; | |
901 } | |
902 | |
903 | |
904 /***************************************************************************** | |
905 initialization code | |
906 ****************************************************************************/ | |
907 | |
908 void | |
909 init_global_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 && !noninteractive) | |
872 | 914 call_critical_lisp_code (d, Qinit_global_faces, wrap_device (d)); |
428 | 915 } |
916 | |
917 void | |
918 init_device_faces (struct device *d) | |
919 { | |
920 /* This function can call lisp */ | |
921 | |
922 /* When making the initial terminal device, there is no Lisp code | |
923 loaded, so we can't do this. */ | |
924 if (initialized) | |
872 | 925 call_critical_lisp_code (d, Qinit_device_faces, wrap_device (d)); |
428 | 926 } |
927 | |
928 void | |
929 init_frame_faces (struct frame *frm) | |
930 { | |
931 /* When making the initial terminal device, there is no Lisp code | |
932 loaded, so we can't do this. */ | |
933 if (initialized) | |
934 { | |
793 | 935 Lisp_Object tframe = wrap_frame (frm); |
936 | |
428 | 937 |
938 /* DO NOT change the selected frame here. If the debugger goes off | |
939 it will try and display on the frame being created, but it is not | |
940 ready for that yet and a horrible death will occur. Any random | |
941 code depending on the selected-frame as an implicit arg should be | |
942 tracked down and shot. For the benefit of the one known, | |
943 xpm-color-symbols, make-frame sets the variable | |
944 Vframe_being_created to the frame it is making and sets it to nil | |
945 when done. Internal functions that this could trigger which are | |
946 currently depending on selected-frame should use this instead. It | |
947 is not currently visible at the lisp level. */ | |
948 call_critical_lisp_code (XDEVICE (FRAME_DEVICE (frm)), | |
949 Qinit_frame_faces, tframe); | |
950 } | |
951 } | |
952 | |
953 | |
954 /**************************************************************************** | |
955 * face cache element functions * | |
956 ****************************************************************************/ | |
957 | |
958 /* | |
959 | |
960 #### Here is a description of how the face cache elements ought | |
961 to be redone. It is *NOT* how they work currently: | |
962 | |
963 However, when I started to go about implementing this, I realized | |
964 that there are all sorts of subtle problems with cache coherency | |
965 that are coming up. As it turns out, these problems don't | |
966 manifest themselves now due to the brute-force "kill 'em all" | |
967 approach to cache invalidation when faces change; but if this | |
968 is ever made smarter, these problems are going to come up, and | |
969 some of them are very non-obvious. | |
970 | |
971 I'm thinking of redoing the cache code a bit to avoid these | |
972 coherency problems. The bulk of the problems will arise because | |
973 the current display structures have simple indices into the | |
974 face cache, but the cache can be changed at various times, | |
975 which could make the current display structures incorrect. | |
976 I guess the dirty and updated flags are an attempt to fix | |
977 this, but this approach doesn't really work. | |
978 | |
979 Here's an approach that should keep things clean and unconfused: | |
980 | |
981 1) Imagine a "virtual face cache" that can grow arbitrarily | |
982 big and for which the only thing allowed is to add new | |
983 elements. Existing elements cannot be removed or changed. | |
984 This way, any pointers in the existing redisplay structure | |
985 into the cache never get screwed up. (This is important | |
986 because even if a cache element is out of date, if there's | |
987 a pointer to it then its contents still accurately describe | |
988 the way the text currently looks on the screen.) | |
989 2) Each element in the virtual cache either describes exactly | |
990 one face, or describes the merger of a number of faces | |
991 by some process. In order to simplify things, for mergers | |
992 we do not record which faces or ordering was used, but | |
993 simply that this cache element is the result of merging. | |
994 Unlike the current implementation, it's important that a | |
995 single cache element not be used to both describe a | |
996 single face and describe a merger, even if all the property | |
997 values are the same. | |
998 3) Each cache element can be clean or dirty. "Dirty" means | |
999 that the face that the element points to has been changed; | |
1000 this gets set at the time the face is changed. This | |
1001 way, when looking up a value in the cache, you can determine | |
1002 whether it's out of date or not. For merged faces it | |
1003 does not matter -- we don't record the faces or priority | |
1004 used to create the merger, so it's impossible to look up | |
1005 one of these faces. We have to recompute it each time. | |
1006 Luckily, this is fine -- doing the merge is much | |
1007 less expensive than recomputing the properties of a | |
1008 single face. | |
1009 4) For each cache element, we keep a hash value. (In order | |
1010 to hash the boolean properties, we convert each of them | |
1011 into a different large prime number so that the hashing works | |
1012 well.) This allows us, when comparing runes, to properly | |
1013 determine whether the face for that rune has changed. | |
1014 This will be especially important for TTY's, where there | |
1015 aren't that many faces and minimizing redraw is very | |
1016 important. | |
1017 5) We can't actually keep an infinite cache, but that doesn't | |
1018 really matter that much. The only elements we care about | |
1019 are those that are used by either the current or desired | |
1020 display structs. Therefore, we keep a per-window | |
1021 redisplay iteration number, and mark each element with | |
1022 that number as we use it. Just after outputting the | |
1023 window and synching the redisplay structs, we go through | |
1024 the cache and invalidate all elements that are not clean | |
1025 elements referring to a particular face and that do not | |
1026 have an iteration number equal to the current one. We | |
1027 keep them in a chain, and use them to allocate new | |
1028 elements when possible instead of increasing the Dynarr. | |
1029 | |
872 | 1030 --ben (?? At least I think I wrote this!) |
428 | 1031 */ |
1032 | |
1033 /* mark for GC a dynarr of face cachels. */ | |
1034 | |
1035 void | |
1036 mark_face_cachels (face_cachel_dynarr *elements) | |
1037 { | |
1038 int elt; | |
1039 | |
1040 if (!elements) | |
1041 return; | |
1042 | |
1043 for (elt = 0; elt < Dynarr_length (elements); elt++) | |
1044 { | |
1045 struct face_cachel *cachel = Dynarr_atp (elements, elt); | |
1046 | |
1047 { | |
1048 int i; | |
1049 | |
1050 for (i = 0; i < NUM_LEADING_BYTES; i++) | |
1051 if (!NILP (cachel->font[i]) && !UNBOUNDP (cachel->font[i])) | |
1052 mark_object (cachel->font[i]); | |
1053 } | |
1054 mark_object (cachel->face); | |
1055 mark_object (cachel->foreground); | |
1056 mark_object (cachel->background); | |
1057 mark_object (cachel->display_table); | |
1058 mark_object (cachel->background_pixmap); | |
1059 } | |
1060 } | |
1061 | |
1062 /* ensure that the given cachel contains an updated font value for | |
1063 the given charset. Return the updated font value. */ | |
1064 | |
1065 Lisp_Object | |
1066 ensure_face_cachel_contains_charset (struct face_cachel *cachel, | |
1067 Lisp_Object domain, Lisp_Object charset) | |
1068 { | |
1069 Lisp_Object new_val; | |
1070 Lisp_Object face = cachel->face; | |
1071 int bound = 1; | |
1072 int offs = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE; | |
1073 | |
1074 if (!UNBOUNDP (cachel->font[offs]) | |
1075 && cachel->font_updated[offs]) | |
1076 return cachel->font[offs]; | |
1077 | |
1078 if (UNBOUNDP (face)) | |
1079 { | |
1080 /* a merged face. */ | |
1081 int i; | |
1082 struct window *w = XWINDOW (domain); | |
1083 | |
1084 new_val = Qunbound; | |
1085 cachel->font_specified[offs] = 0; | |
1086 for (i = 0; i < cachel->nfaces; i++) | |
1087 { | |
1088 struct face_cachel *oth; | |
1089 | |
1090 oth = Dynarr_atp (w->face_cachels, | |
1091 FACE_CACHEL_FINDEX_UNSAFE (cachel, i)); | |
1092 /* Tout le monde aime la recursion */ | |
1093 ensure_face_cachel_contains_charset (oth, domain, charset); | |
1094 | |
1095 if (oth->font_specified[offs]) | |
1096 { | |
1097 new_val = oth->font[offs]; | |
1098 cachel->font_specified[offs] = 1; | |
1099 break; | |
1100 } | |
1101 } | |
1102 | |
1103 if (!cachel->font_specified[offs]) | |
1104 /* need to do the default face. */ | |
1105 { | |
1106 struct face_cachel *oth = | |
1107 Dynarr_atp (w->face_cachels, DEFAULT_INDEX); | |
1108 ensure_face_cachel_contains_charset (oth, domain, charset); | |
1109 | |
1110 new_val = oth->font[offs]; | |
1111 } | |
1112 | |
1113 if (!UNBOUNDP (cachel->font[offs]) && !EQ (cachel->font[offs], new_val)) | |
1114 cachel->dirty = 1; | |
1115 cachel->font_updated[offs] = 1; | |
1116 cachel->font[offs] = new_val; | |
1117 return new_val; | |
1118 } | |
1119 | |
1120 new_val = face_property_matching_instance (face, Qfont, charset, domain, | |
793 | 1121 /* #### look into error flag */ |
1122 ERROR_ME_DEBUG_WARN, 1, Qzero); | |
428 | 1123 if (UNBOUNDP (new_val)) |
1124 { | |
1125 bound = 0; | |
1126 new_val = face_property_matching_instance (face, Qfont, | |
1127 charset, domain, | |
793 | 1128 /* #### look into error |
1129 flag */ | |
1130 ERROR_ME_DEBUG_WARN, 0, | |
1131 Qzero); | |
428 | 1132 } |
1133 if (!UNBOUNDP (cachel->font[offs]) && !EQ (new_val, cachel->font[offs])) | |
1134 cachel->dirty = 1; | |
1135 cachel->font_updated[offs] = 1; | |
1136 cachel->font[offs] = new_val; | |
1137 cachel->font_specified[offs] = (bound || EQ (face, Vdefault_face)); | |
1138 return new_val; | |
1139 } | |
1140 | |
1141 /* Ensure that the given cachel contains updated fonts for all | |
1142 the charsets specified. */ | |
1143 | |
1144 void | |
1145 ensure_face_cachel_complete (struct face_cachel *cachel, | |
1146 Lisp_Object domain, unsigned char *charsets) | |
1147 { | |
1148 int i; | |
1149 | |
1150 for (i = 0; i < NUM_LEADING_BYTES; i++) | |
1151 if (charsets[i]) | |
1152 { | |
826 | 1153 Lisp_Object charset = charset_by_leading_byte (i + MIN_LEADING_BYTE); |
428 | 1154 assert (CHARSETP (charset)); |
1155 ensure_face_cachel_contains_charset (cachel, domain, charset); | |
1156 } | |
1157 } | |
1158 | |
1159 void | |
1160 face_cachel_charset_font_metric_info (struct face_cachel *cachel, | |
1161 unsigned char *charsets, | |
1162 struct font_metric_info *fm) | |
1163 { | |
1164 int i; | |
1165 | |
1166 fm->width = 1; | |
1167 fm->height = fm->ascent = 1; | |
1168 fm->descent = 0; | |
1169 fm->proportional_p = 0; | |
1170 | |
1171 for (i = 0; i < NUM_LEADING_BYTES; i++) | |
1172 { | |
1173 if (charsets[i]) | |
1174 { | |
826 | 1175 Lisp_Object charset = charset_by_leading_byte (i + MIN_LEADING_BYTE); |
428 | 1176 Lisp_Object font_instance = FACE_CACHEL_FONT (cachel, charset); |
440 | 1177 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_instance); |
428 | 1178 |
1179 assert (CHARSETP (charset)); | |
1180 assert (FONT_INSTANCEP (font_instance)); | |
1181 | |
1182 if (fm->ascent < (int) fi->ascent) fm->ascent = (int) fi->ascent; | |
1183 if (fm->descent < (int) fi->descent) fm->descent = (int) fi->descent; | |
1184 fm->height = fm->ascent + fm->descent; | |
1185 if (fi->proportional_p) | |
1186 fm->proportional_p = 1; | |
1187 if (EQ (charset, Vcharset_ascii)) | |
1188 fm->width = fi->width; | |
1189 } | |
1190 } | |
1191 } | |
1192 | |
1193 #define FROB(field) \ | |
1194 do { \ | |
1195 Lisp_Object new_val = \ | |
1196 FACE_PROPERTY_INSTANCE (face, Q##field, domain, 1, Qzero); \ | |
1197 int bound = 1; \ | |
1198 if (UNBOUNDP (new_val)) \ | |
1199 { \ | |
1200 bound = 0; \ | |
1201 new_val = FACE_PROPERTY_INSTANCE (face, Q##field, domain, 0, Qzero); \ | |
1202 } \ | |
1203 if (!EQ (new_val, cachel->field)) \ | |
1204 { \ | |
1205 cachel->field = new_val; \ | |
1206 cachel->dirty = 1; \ | |
1207 } \ | |
1208 cachel->field##_specified = (bound || default_face); \ | |
1209 } while (0) | |
1210 | |
446 | 1211 /* |
1212 * A face's background pixmap will override the face's | |
1213 * background color. But the background pixmap of the | |
1214 * default face should not override the background color of | |
1215 * a face if the background color has been specified or | |
1216 * inherited. | |
1217 * | |
1218 * To accomplish this we remove the background pixmap of the | |
1219 * cachel and mark it as having been specified so that cachel | |
1220 * merging won't override it later. | |
1221 */ | |
1222 #define MAYBE_UNFROB_BACKGROUND_PIXMAP \ | |
1223 do \ | |
1224 { \ | |
1225 if (! default_face \ | |
1226 && cachel->background_specified \ | |
1227 && ! cachel->background_pixmap_specified) \ | |
1228 { \ | |
1229 cachel->background_pixmap = Qunbound; \ | |
1230 cachel->background_pixmap_specified = 1; \ | |
1231 } \ | |
1232 } while (0) | |
1233 | |
1234 | |
1235 /* Add a cachel for the given face to the given window's cache. */ | |
1236 | |
1237 static void | |
1238 add_face_cachel (struct window *w, Lisp_Object face) | |
1239 { | |
1240 int must_finish_frobbing = ! WINDOW_FACE_CACHEL (w, DEFAULT_INDEX); | |
1241 struct face_cachel new_cachel; | |
1242 Lisp_Object domain; | |
1243 | |
1244 reset_face_cachel (&new_cachel); | |
793 | 1245 domain = wrap_window (w); |
446 | 1246 update_face_cachel_data (&new_cachel, domain, face); |
1247 Dynarr_add (w->face_cachels, new_cachel); | |
1248 | |
1249 /* The face's background pixmap have not yet been frobbed (see comment | |
1250 int update_face_cachel_data), so we have to do it now */ | |
1251 if (must_finish_frobbing) | |
1252 { | |
1253 int default_face = EQ (face, Vdefault_face); | |
1254 struct face_cachel *cachel | |
1255 = Dynarr_atp (w->face_cachels, Dynarr_length (w->face_cachels) - 1); | |
1256 | |
1257 FROB (background_pixmap); | |
1258 MAYBE_UNFROB_BACKGROUND_PIXMAP; | |
1259 } | |
1260 } | |
1261 | |
1262 /* Called when the updated flag has been cleared on a cachel. | |
1263 This function returns 1 if the caller must finish the update (see comment | |
1264 below), 0 otherwise. | |
1265 */ | |
1266 | |
1267 void | |
1268 update_face_cachel_data (struct face_cachel *cachel, | |
1269 Lisp_Object domain, | |
1270 Lisp_Object face) | |
1271 { | |
1272 if (XFACE (face)->dirty || UNBOUNDP (cachel->face)) | |
1273 { | |
1274 int default_face = EQ (face, Vdefault_face); | |
1275 cachel->face = face; | |
1276 | |
1277 /* We normally only set the _specified flags if the value was | |
1278 actually bound. The exception is for the default face where | |
1279 we always set it since it is the ultimate fallback. */ | |
1280 | |
428 | 1281 FROB (foreground); |
1282 FROB (background); | |
1283 FROB (display_table); | |
446 | 1284 |
1285 /* #### WARNING: the background pixmap property of faces is currently | |
1286 the only one dealing with images. The problem we have here is that | |
1287 frobbing the background pixmap might lead to image instantiation | |
1288 which in turn might require that the cache we're building be up to | |
1289 date, hence a crash. Here's a typical scenario of this: | |
1290 | |
1291 - a new window is created and it's face cache elements are | |
1292 initialized through a call to reset_face_cachels[1]. At that point, | |
1293 the cache for the default and modeline faces (normaly taken care of | |
1294 by redisplay itself) are null. | |
1295 - the default face has a background pixmap which needs to be | |
1296 instantiated right here, as a consequence of cache initialization. | |
1297 - the background pixmap image happens to be instantiated as a string | |
1298 (this happens on tty's for instance). | |
1299 - In order to do this, we need to compute the string geometry. | |
1300 - In order to do this, we might have to access the window's default | |
1301 face cache. But this is the cache we're building right now, it is | |
1302 null. | |
1303 - BARF !!!!! | |
428 | 1304 |
446 | 1305 To sum up, this means that it is in general unsafe to instantiate |
1306 images before face cache updating is complete (appart from image | |
1307 related face attributes). The solution we use below is to actually | |
1308 detect whether we're building the window's face_cachels for the first | |
1309 time, and simply NOT frob the background pixmap in that case. If | |
1310 other image-related face attributes are ever implemented, they should | |
1311 be protected the same way right here. | |
1312 | |
1313 One note: | |
1314 * See comment in `default_face_font_info' in face.c. Who wrote it ? | |
1315 Maybe we have the begining of an answer here ? | |
1316 | |
1317 Footnotes: | |
1318 [1] See comment at the top of `allocate_window' in window.c. | |
1319 | |
1320 -- didier | |
1321 */ | |
1322 if (! WINDOWP (domain) | |
1323 || WINDOW_FACE_CACHEL (DOMAIN_XWINDOW (domain), DEFAULT_INDEX)) | |
428 | 1324 { |
446 | 1325 FROB (background_pixmap); |
1326 MAYBE_UNFROB_BACKGROUND_PIXMAP; | |
428 | 1327 } |
1328 #undef FROB | |
446 | 1329 #undef MAYBE_UNFROB_BACKGROUND_PIXMAP |
428 | 1330 |
1331 ensure_face_cachel_contains_charset (cachel, domain, Vcharset_ascii); | |
1332 | |
1333 #define FROB(field) \ | |
1334 do { \ | |
1335 Lisp_Object new_val = \ | |
1336 FACE_PROPERTY_INSTANCE (face, Q##field, domain, 1, Qzero); \ | |
1337 int bound = 1; \ | |
1338 unsigned int new_val_int; \ | |
1339 if (UNBOUNDP (new_val)) \ | |
1340 { \ | |
1341 bound = 0; \ | |
1342 new_val = FACE_PROPERTY_INSTANCE (face, Q##field, domain, 0, Qzero); \ | |
1343 } \ | |
1344 new_val_int = EQ (new_val, Qt); \ | |
1345 if (cachel->field != new_val_int) \ | |
1346 { \ | |
1347 cachel->field = new_val_int; \ | |
1348 cachel->dirty = 1; \ | |
1349 } \ | |
1350 cachel->field##_specified = bound; \ | |
1351 } while (0) | |
1352 | |
1353 FROB (underline); | |
1354 FROB (strikethru); | |
1355 FROB (highlight); | |
1356 FROB (dim); | |
1357 FROB (reverse); | |
1358 FROB (blinking); | |
1359 #undef FROB | |
1360 } | |
1361 | |
1362 cachel->updated = 1; | |
1363 } | |
1364 | |
1365 /* Merge the cachel identified by FINDEX in window W into the given | |
1366 cachel. */ | |
1367 | |
1368 static void | |
1369 merge_face_cachel_data (struct window *w, face_index findex, | |
1370 struct face_cachel *cachel) | |
1371 { | |
1372 #define FINDEX_FIELD(field) \ | |
1373 Dynarr_atp (w->face_cachels, findex)->field | |
1374 | |
1375 #define FROB(field) \ | |
1376 do { \ | |
1377 if (!cachel->field##_specified && FINDEX_FIELD (field##_specified)) \ | |
1378 { \ | |
1379 cachel->field = FINDEX_FIELD (field); \ | |
1380 cachel->field##_specified = 1; \ | |
1381 cachel->dirty = 1; \ | |
1382 } \ | |
1383 } while (0) | |
1384 | |
1385 FROB (foreground); | |
1386 FROB (background); | |
1387 FROB (display_table); | |
1388 FROB (background_pixmap); | |
1389 FROB (underline); | |
1390 FROB (strikethru); | |
1391 FROB (highlight); | |
1392 FROB (dim); | |
1393 FROB (reverse); | |
1394 FROB (blinking); | |
1395 /* And do ASCII, of course. */ | |
1396 { | |
1397 int offs = LEADING_BYTE_ASCII - MIN_LEADING_BYTE; | |
1398 | |
1399 if (!cachel->font_specified[offs] && FINDEX_FIELD (font_specified[offs])) | |
1400 { | |
1401 cachel->font[offs] = FINDEX_FIELD (font[offs]); | |
1402 cachel->font_specified[offs] = 1; | |
1403 cachel->dirty = 1; | |
1404 } | |
1405 } | |
1406 | |
1407 #undef FROB | |
1408 #undef FINDEX_FIELD | |
1409 | |
1410 cachel->updated = 1; | |
1411 } | |
1412 | |
1413 /* Initialize a cachel. */ | |
1414 | |
1415 void | |
1416 reset_face_cachel (struct face_cachel *cachel) | |
1417 { | |
1418 xzero (*cachel); | |
1419 cachel->face = Qunbound; | |
1420 cachel->nfaces = 0; | |
1421 cachel->merged_faces = 0; | |
1422 cachel->foreground = Qunbound; | |
1423 cachel->background = Qunbound; | |
1424 { | |
1425 int i; | |
1426 | |
1427 for (i = 0; i < NUM_LEADING_BYTES; i++) | |
1428 cachel->font[i] = Qunbound; | |
1429 } | |
1430 cachel->display_table = Qunbound; | |
1431 cachel->background_pixmap = Qunbound; | |
1432 } | |
1433 | |
1434 /* Retrieve the index to a cachel for window W that corresponds to | |
1435 the specified face. If necessary, add a new element to the | |
1436 cache. */ | |
1437 | |
1438 face_index | |
1439 get_builtin_face_cache_index (struct window *w, Lisp_Object face) | |
1440 { | |
1441 int elt; | |
1442 | |
1443 if (noninteractive) | |
1444 return 0; | |
1445 | |
1446 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++) | |
1447 { | |
1448 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, elt); | |
1449 | |
1450 if (EQ (cachel->face, face)) | |
1451 { | |
793 | 1452 Lisp_Object window = wrap_window (w); |
1453 | |
428 | 1454 if (!cachel->updated) |
1455 update_face_cachel_data (cachel, window, face); | |
1456 return elt; | |
1457 } | |
1458 } | |
1459 | |
1460 /* If we didn't find the face, add it and then return its index. */ | |
1461 add_face_cachel (w, face); | |
1462 return elt; | |
1463 } | |
1464 | |
1465 void | |
1466 reset_face_cachels (struct window *w) | |
1467 { | |
1468 /* #### Not initialized in batch mode for the stream device. */ | |
1469 if (w->face_cachels) | |
1470 { | |
1471 int i; | |
1472 | |
1473 for (i = 0; i < Dynarr_length (w->face_cachels); i++) | |
1474 { | |
1475 struct face_cachel *cachel = Dynarr_atp (w->face_cachels, i); | |
1476 if (cachel->merged_faces) | |
1477 Dynarr_free (cachel->merged_faces); | |
1478 } | |
1479 Dynarr_reset (w->face_cachels); | |
1480 get_builtin_face_cache_index (w, Vdefault_face); | |
1481 get_builtin_face_cache_index (w, Vmodeline_face); | |
1482 XFRAME (w->frame)->window_face_cache_reset = 1; | |
1483 } | |
1484 } | |
1485 | |
1486 void | |
1487 mark_face_cachels_as_clean (struct window *w) | |
1488 { | |
1489 int elt; | |
1490 | |
1491 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++) | |
1492 Dynarr_atp (w->face_cachels, elt)->dirty = 0; | |
1493 } | |
1494 | |
1495 void | |
1496 mark_face_cachels_as_not_updated (struct window *w) | |
1497 { | |
1498 int elt; | |
1499 | |
1500 for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++) | |
1501 { | |
1502 struct face_cachel *cachel = Dynarr_atp (w->face_cachels, elt); | |
1503 int i; | |
1504 | |
1505 cachel->updated = 0; | |
1506 for (i = 0; i < NUM_LEADING_BYTES; i++) | |
1507 cachel->font_updated[i] = 0; | |
1508 } | |
1509 } | |
1510 | |
1511 #ifdef MEMORY_USAGE_STATS | |
1512 | |
1513 int | |
1514 compute_face_cachel_usage (face_cachel_dynarr *face_cachels, | |
1515 struct overhead_stats *ovstats) | |
1516 { | |
1517 int total = 0; | |
1518 | |
1519 if (face_cachels) | |
1520 { | |
1521 int i; | |
1522 | |
1523 total += Dynarr_memory_usage (face_cachels, ovstats); | |
1524 for (i = 0; i < Dynarr_length (face_cachels); i++) | |
1525 { | |
1526 int_dynarr *merged = Dynarr_at (face_cachels, i).merged_faces; | |
1527 if (merged) | |
1528 total += Dynarr_memory_usage (merged, ovstats); | |
1529 } | |
1530 } | |
1531 | |
1532 return total; | |
1533 } | |
1534 | |
1535 #endif /* MEMORY_USAGE_STATS */ | |
1536 | |
1537 | |
1538 /***************************************************************************** | |
1539 * merged face functions * | |
1540 *****************************************************************************/ | |
1541 | |
1542 /* Compare two merged face cachels to determine whether we have to add | |
1543 a new entry to the face cache. | |
1544 | |
1545 Note that we do not compare the attributes, but just the faces the | |
1546 cachels are based on. If they are the same, then the cachels certainly | |
1547 ought to have the same attributes, except in the case where fonts | |
1548 for different charsets have been determined in the two -- and in that | |
1549 case this difference is fine. */ | |
1550 | |
1551 static int | |
1552 compare_merged_face_cachels (struct face_cachel *cachel1, | |
1553 struct face_cachel *cachel2) | |
1554 { | |
1555 int i; | |
1556 | |
1557 if (!EQ (cachel1->face, cachel2->face) | |
1558 || cachel1->nfaces != cachel2->nfaces) | |
1559 return 0; | |
1560 | |
1561 for (i = 0; i < cachel1->nfaces; i++) | |
1562 if (FACE_CACHEL_FINDEX_UNSAFE (cachel1, i) | |
1563 != FACE_CACHEL_FINDEX_UNSAFE (cachel2, i)) | |
1564 return 0; | |
1565 | |
1566 return 1; | |
1567 } | |
1568 | |
1569 /* Retrieve the index to a cachel for window W that corresponds to | |
1570 the specified cachel. If necessary, add a new element to the | |
1571 cache. This is similar to get_builtin_face_cache_index() but | |
1572 is intended for merged cachels rather than for cachels representing | |
1573 just a face. | |
1574 | |
1575 Note that a merged cachel for just one face is not the same as | |
1576 the simple cachel for that face, because it is also merged with | |
1577 the default face. */ | |
1578 | |
1579 static face_index | |
1580 get_merged_face_cache_index (struct window *w, | |
1581 struct face_cachel *merged_cachel) | |
1582 { | |
1583 int elt; | |
1584 int cache_size = Dynarr_length (w->face_cachels); | |
1585 | |
1586 for (elt = 0; elt < cache_size; elt++) | |
1587 { | |
1588 struct face_cachel *cachel = | |
1589 Dynarr_atp (w->face_cachels, elt); | |
1590 | |
1591 if (compare_merged_face_cachels (cachel, merged_cachel)) | |
1592 return elt; | |
1593 } | |
1594 | |
1595 /* We didn't find it so add this instance to the cache. */ | |
1596 merged_cachel->updated = 1; | |
1597 merged_cachel->dirty = 1; | |
1598 Dynarr_add (w->face_cachels, *merged_cachel); | |
1599 return cache_size; | |
1600 } | |
1601 | |
1602 face_index | |
1603 get_extent_fragment_face_cache_index (struct window *w, | |
1604 struct extent_fragment *ef) | |
1605 { | |
1606 struct face_cachel cachel; | |
1607 int len = Dynarr_length (ef->extents); | |
1608 face_index findex = 0; | |
1609 | |
1610 /* Optimize the default case. */ | |
1611 if (len == 0) | |
1612 return DEFAULT_INDEX; | |
1613 else | |
1614 { | |
1615 int i; | |
1616 | |
1617 /* Merge the faces of the extents together in order. */ | |
1618 | |
1619 reset_face_cachel (&cachel); | |
1620 | |
1621 for (i = len - 1; i >= 0; i--) | |
1622 { | |
1623 EXTENT current = Dynarr_at (ef->extents, i); | |
1624 int has_findex = 0; | |
1625 Lisp_Object face = extent_face (current); | |
1626 | |
1627 if (FACEP (face)) | |
1628 { | |
1629 findex = get_builtin_face_cache_index (w, face); | |
1630 has_findex = 1; | |
1631 merge_face_cachel_data (w, findex, &cachel); | |
1632 } | |
1633 /* remember, we're called from within redisplay | |
1634 so we can't error. */ | |
1635 else while (CONSP (face)) | |
1636 { | |
1637 Lisp_Object one_face = XCAR (face); | |
1638 if (FACEP (one_face)) | |
1639 { | |
1640 findex = get_builtin_face_cache_index (w, one_face); | |
1641 merge_face_cachel_data (w, findex, &cachel); | |
1642 | |
1643 /* code duplication here but there's no clean | |
1644 way to avoid it. */ | |
1645 if (cachel.nfaces >= NUM_STATIC_CACHEL_FACES) | |
1646 { | |
1647 if (!cachel.merged_faces) | |
1648 cachel.merged_faces = Dynarr_new (int); | |
1649 Dynarr_add (cachel.merged_faces, findex); | |
1650 } | |
1651 else | |
1652 cachel.merged_faces_static[cachel.nfaces] = findex; | |
1653 cachel.nfaces++; | |
1654 } | |
1655 face = XCDR (face); | |
1656 } | |
1657 | |
1658 if (has_findex) | |
1659 { | |
1660 if (cachel.nfaces >= NUM_STATIC_CACHEL_FACES) | |
1661 { | |
1662 if (!cachel.merged_faces) | |
1663 cachel.merged_faces = Dynarr_new (int); | |
1664 Dynarr_add (cachel.merged_faces, findex); | |
1665 } | |
1666 else | |
1667 cachel.merged_faces_static[cachel.nfaces] = findex; | |
1668 cachel.nfaces++; | |
1669 } | |
1670 } | |
1671 | |
1672 /* Now finally merge in the default face. */ | |
1673 findex = get_builtin_face_cache_index (w, Vdefault_face); | |
1674 merge_face_cachel_data (w, findex, &cachel); | |
1675 | |
444 | 1676 findex = get_merged_face_cache_index (w, &cachel); |
1677 if (cachel.merged_faces && | |
1678 /* merged_faces did not get stored and available via return value */ | |
1679 Dynarr_at (w->face_cachels, findex).merged_faces != | |
1680 cachel.merged_faces) | |
1681 { | |
1682 Dynarr_free (cachel.merged_faces); | |
1683 cachel.merged_faces = 0; | |
1684 } | |
1685 return findex; | |
428 | 1686 } |
1687 } | |
1688 | |
1689 | |
1690 /***************************************************************************** | |
1691 interface functions | |
1692 ****************************************************************************/ | |
1693 | |
1694 static void | |
1695 update_EmacsFrame (Lisp_Object frame, Lisp_Object name) | |
1696 { | |
1697 struct frame *frm = XFRAME (frame); | |
1698 | |
1699 if (EQ (name, Qfont)) | |
1700 MARK_FRAME_SIZE_SLIPPED (frm); | |
1701 | |
1702 MAYBE_FRAMEMETH (frm, update_frame_external_traits, (frm, name)); | |
1703 } | |
1704 | |
1705 static void | |
1706 update_EmacsFrames (Lisp_Object locale, Lisp_Object name) | |
1707 { | |
1708 if (FRAMEP (locale)) | |
1709 { | |
1710 update_EmacsFrame (locale, name); | |
1711 } | |
1712 else if (DEVICEP (locale)) | |
1713 { | |
1714 Lisp_Object frmcons; | |
1715 | |
1716 DEVICE_FRAME_LOOP (frmcons, XDEVICE (locale)) | |
1717 update_EmacsFrame (XCAR (frmcons), name); | |
1718 } | |
1719 else if (EQ (locale, Qglobal) || EQ (locale, Qfallback)) | |
1720 { | |
1721 Lisp_Object frmcons, devcons, concons; | |
1722 | |
1723 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons) | |
1724 update_EmacsFrame (XCAR (frmcons), name); | |
1725 } | |
1726 } | |
1727 | |
1728 void | |
1729 update_frame_face_values (struct frame *f) | |
1730 { | |
793 | 1731 Lisp_Object frm = wrap_frame (f); |
428 | 1732 |
1733 update_EmacsFrame (frm, Qforeground); | |
1734 update_EmacsFrame (frm, Qbackground); | |
1735 update_EmacsFrame (frm, Qfont); | |
1736 } | |
1737 | |
1738 void | |
1739 face_property_was_changed (Lisp_Object face, Lisp_Object property, | |
1740 Lisp_Object locale) | |
1741 { | |
1742 int default_face = EQ (face, Vdefault_face); | |
1743 | |
1744 /* If the locale could affect the frame value, then call | |
1745 update_EmacsFrames just in case. */ | |
1746 if (default_face && | |
1747 (EQ (property, Qforeground) || | |
1748 EQ (property, Qbackground) || | |
1749 EQ (property, Qfont))) | |
1750 update_EmacsFrames (locale, property); | |
1751 | |
1752 if (WINDOWP (locale)) | |
1753 { | |
1754 MARK_FRAME_FACES_CHANGED (XFRAME (XWINDOW (locale)->frame)); | |
1755 } | |
1756 else if (FRAMEP (locale)) | |
1757 { | |
1758 MARK_FRAME_FACES_CHANGED (XFRAME (locale)); | |
1759 } | |
1760 else if (DEVICEP (locale)) | |
1761 { | |
1762 MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (locale)); | |
1763 } | |
1764 else | |
1765 { | |
1766 Lisp_Object devcons, concons; | |
1767 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
1768 MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (XCAR (devcons))); | |
1769 } | |
1770 | |
1771 /* | |
1772 * This call to update_faces_inheritance isn't needed and makes | |
1773 * creating and modifying faces _very_ slow. The point of | |
1774 * update_face_inheritances is to find all faces that inherit | |
1775 * directly from this face property and set the specifier "dirty" | |
1776 * flag on the corresponding specifier. This forces recaching of | |
1777 * cached specifier values in frame and window struct slots. But | |
1778 * currently no face properties are cached in frame and window | |
1779 * struct slots, so calling this function does nothing useful! | |
1780 * | |
1781 * Further, since update_faces_inheritance maps over the whole | |
1782 * face table every time it is called, it gets terribly slow when | |
1783 * there are many faces. Creating 500 faces on a 50Mhz 486 took | |
1784 * 433 seconds when update_faces_inheritance was called. With the | |
1785 * call commented out, creating those same 500 faces took 0.72 | |
1786 * seconds. | |
1787 */ | |
1788 /* update_faces_inheritance (face, property);*/ | |
1789 XFACE (face)->dirty = 1; | |
1790 } | |
1791 | |
1792 DEFUN ("copy-face", Fcopy_face, 2, 6, 0, /* | |
1793 Define and return a new face which is a copy of an existing one, | |
1794 or makes an already-existing face be exactly like another. | |
1795 LOCALE, TAG-SET, EXACT-P, and HOW-TO-ADD are as in `copy-specifier'. | |
1796 */ | |
1797 (old_face, new_name, locale, tag_set, exact_p, how_to_add)) | |
1798 { | |
440 | 1799 Lisp_Face *fold, *fnew; |
428 | 1800 Lisp_Object new_face = Qnil; |
1801 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
1802 | |
1803 old_face = Fget_face (old_face); | |
1804 | |
1805 /* We GCPRO old_face because it might be temporary, and GCing could | |
1806 occur in various places below. */ | |
1807 GCPRO4 (tag_set, locale, old_face, new_face); | |
1808 /* check validity of how_to_add now. */ | |
1809 decode_how_to_add_specification (how_to_add); | |
1810 /* and of tag_set. */ | |
1811 tag_set = decode_specifier_tag_set (tag_set); | |
1812 /* and of locale. */ | |
1813 locale = decode_locale_list (locale); | |
1814 | |
1815 new_face = Ffind_face (new_name); | |
1816 if (NILP (new_face)) | |
1817 { | |
1818 Lisp_Object temp; | |
1819 | |
1820 CHECK_SYMBOL (new_name); | |
1821 | |
1822 /* Create the new face with the same status as the old face. */ | |
1823 temp = (NILP (Fgethash (old_face, Vtemporary_faces_cache, Qnil)) | |
1824 ? Qnil | |
1825 : Qt); | |
1826 | |
1827 new_face = Fmake_face (new_name, Qnil, temp); | |
1828 } | |
1829 | |
1830 fold = XFACE (old_face); | |
1831 fnew = XFACE (new_face); | |
1832 | |
1833 #define COPY_PROPERTY(property) \ | |
1834 Fcopy_specifier (fold->property, fnew->property, \ | |
1835 locale, tag_set, exact_p, how_to_add); | |
1836 | |
1837 COPY_PROPERTY (foreground); | |
1838 COPY_PROPERTY (background); | |
1839 COPY_PROPERTY (font); | |
1840 COPY_PROPERTY (display_table); | |
1841 COPY_PROPERTY (background_pixmap); | |
1842 COPY_PROPERTY (underline); | |
1843 COPY_PROPERTY (strikethru); | |
1844 COPY_PROPERTY (highlight); | |
1845 COPY_PROPERTY (dim); | |
1846 COPY_PROPERTY (blinking); | |
1847 COPY_PROPERTY (reverse); | |
1848 #undef COPY_PROPERTY | |
1849 /* #### should it copy the individual specifiers, if they exist? */ | |
1850 fnew->plist = Fcopy_sequence (fold->plist); | |
1851 | |
1852 UNGCPRO; | |
1853 | |
1854 return new_name; | |
1855 } | |
1856 | |
1857 | |
1858 void | |
1859 syms_of_faces (void) | |
1860 { | |
5117
3742ea8250b5
Checking in final CVS version of workspace 'ben-lisp-object'
Ben Wing <ben@xemacs.org>
parents:
3017
diff
changeset
|
1861 INIT_LISP_OBJECT (face); |
442 | 1862 |
440 | 1863 /* Qdefault, Qwidget, Qleft_margin, Qright_margin defined in general.c */ |
563 | 1864 DEFSYMBOL (Qmodeline); |
1865 DEFSYMBOL (Qgui_element); | |
1866 DEFSYMBOL (Qtext_cursor); | |
1867 DEFSYMBOL (Qvertical_divider); | |
428 | 1868 |
1869 DEFSUBR (Ffacep); | |
1870 DEFSUBR (Ffind_face); | |
1871 DEFSUBR (Fget_face); | |
1872 DEFSUBR (Fface_name); | |
1873 DEFSUBR (Fbuilt_in_face_specifiers); | |
1874 DEFSUBR (Fface_list); | |
1875 DEFSUBR (Fmake_face); | |
1876 DEFSUBR (Fcopy_face); | |
1877 | |
563 | 1878 DEFSYMBOL (Qfacep); |
1879 DEFSYMBOL (Qforeground); | |
1880 DEFSYMBOL (Qbackground); | |
428 | 1881 /* Qfont defined in general.c */ |
563 | 1882 DEFSYMBOL (Qdisplay_table); |
1883 DEFSYMBOL (Qbackground_pixmap); | |
1884 DEFSYMBOL (Qunderline); | |
1885 DEFSYMBOL (Qstrikethru); | |
428 | 1886 /* Qhighlight, Qreverse defined in general.c */ |
563 | 1887 DEFSYMBOL (Qdim); |
1888 DEFSYMBOL (Qblinking); | |
428 | 1889 |
2865 | 1890 DEFSYMBOL (Qface_alias); |
2867 | 1891 DEFERROR_STANDARD (Qcyclic_face_alias, Qinvalid_state); |
2865 | 1892 |
563 | 1893 DEFSYMBOL (Qinit_face_from_resources); |
1894 DEFSYMBOL (Qinit_global_faces); | |
1895 DEFSYMBOL (Qinit_device_faces); | |
1896 DEFSYMBOL (Qinit_frame_faces); | |
428 | 1897 } |
1898 | |
1899 void | |
1900 structure_type_create_faces (void) | |
1901 { | |
1902 struct structure_type *st; | |
1903 | |
1904 st = define_structure_type (Qface, face_validate, face_instantiate); | |
1905 | |
1906 define_structure_type_keyword (st, Qname, face_name_validate); | |
1907 } | |
1908 | |
1909 void | |
1910 vars_of_faces (void) | |
1911 { | |
1912 staticpro (&Vpermanent_faces_cache); | |
771 | 1913 Vpermanent_faces_cache = |
1914 make_lisp_hash_table (10, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ); | |
428 | 1915 staticpro (&Vtemporary_faces_cache); |
771 | 1916 Vtemporary_faces_cache = |
1917 make_lisp_hash_table (0, HASH_TABLE_WEAK, HASH_TABLE_EQ); | |
428 | 1918 |
1919 staticpro (&Vdefault_face); | |
1920 Vdefault_face = Qnil; | |
1921 staticpro (&Vgui_element_face); | |
1922 Vgui_element_face = Qnil; | |
1923 staticpro (&Vwidget_face); | |
1924 Vwidget_face = Qnil; | |
1925 staticpro (&Vmodeline_face); | |
1926 Vmodeline_face = Qnil; | |
1927 staticpro (&Vtoolbar_face); | |
1928 Vtoolbar_face = Qnil; | |
1929 | |
1930 staticpro (&Vvertical_divider_face); | |
1931 Vvertical_divider_face = Qnil; | |
1932 staticpro (&Vleft_margin_face); | |
1933 Vleft_margin_face = Qnil; | |
1934 staticpro (&Vright_margin_face); | |
1935 Vright_margin_face = Qnil; | |
1936 staticpro (&Vtext_cursor_face); | |
1937 Vtext_cursor_face = Qnil; | |
1938 staticpro (&Vpointer_face); | |
1939 Vpointer_face = Qnil; | |
1940 | |
1941 { | |
1942 Lisp_Object syms[20]; | |
1943 int n = 0; | |
1944 | |
1945 syms[n++] = Qforeground; | |
1946 syms[n++] = Qbackground; | |
1947 syms[n++] = Qfont; | |
1948 syms[n++] = Qdisplay_table; | |
1949 syms[n++] = Qbackground_pixmap; | |
1950 syms[n++] = Qunderline; | |
1951 syms[n++] = Qstrikethru; | |
1952 syms[n++] = Qhighlight; | |
1953 syms[n++] = Qdim; | |
1954 syms[n++] = Qblinking; | |
1955 syms[n++] = Qreverse; | |
1956 | |
1957 Vbuilt_in_face_specifiers = Flist (n, syms); | |
1958 staticpro (&Vbuilt_in_face_specifiers); | |
1959 } | |
1960 } | |
1961 | |
1962 void | |
1963 complex_vars_of_faces (void) | |
1964 { | |
1965 /* Create the default face now so we know what it is immediately. */ | |
1966 | |
1967 Vdefault_face = Qnil; /* so that Fmake_face() doesn't set up a bogus | |
1968 default value */ | |
771 | 1969 Vdefault_face = Fmake_face (Qdefault, build_msg_string ("default face"), |
428 | 1970 Qnil); |
1971 | |
1972 /* Provide some last-resort fallbacks to avoid utter fuckage if | |
1973 someone provides invalid values for the global specifications. */ | |
1974 | |
1975 { | |
1976 Lisp_Object fg_fb = Qnil, bg_fb = Qnil; | |
1977 | |
462 | 1978 #ifdef HAVE_GTK |
1979 fg_fb = acons (list1 (Qgtk), build_string ("black"), fg_fb); | |
1980 bg_fb = acons (list1 (Qgtk), build_string ("white"), bg_fb); | |
1981 #endif | |
428 | 1982 #ifdef HAVE_X_WINDOWS |
1983 fg_fb = acons (list1 (Qx), build_string ("black"), fg_fb); | |
1984 bg_fb = acons (list1 (Qx), build_string ("white"), bg_fb); | |
1985 #endif | |
1986 #ifdef HAVE_TTY | |
1987 fg_fb = acons (list1 (Qtty), Fvector (0, 0), fg_fb); | |
1988 bg_fb = acons (list1 (Qtty), Fvector (0, 0), bg_fb); | |
1989 #endif | |
1990 #ifdef HAVE_MS_WINDOWS | |
440 | 1991 fg_fb = acons (list1 (Qmsprinter), build_string ("black"), fg_fb); |
1992 bg_fb = acons (list1 (Qmsprinter), build_string ("white"), bg_fb); | |
428 | 1993 fg_fb = acons (list1 (Qmswindows), build_string ("black"), fg_fb); |
1994 bg_fb = acons (list1 (Qmswindows), build_string ("white"), bg_fb); | |
1995 #endif | |
1996 set_specifier_fallback (Fget (Vdefault_face, Qforeground, Qnil), fg_fb); | |
1997 set_specifier_fallback (Fget (Vdefault_face, Qbackground, Qnil), bg_fb); | |
1998 } | |
1999 | |
2000 /* #### We may want to have different fallback values if NeXTstep | |
2001 support is compiled in. */ | |
2002 { | |
2003 Lisp_Object inst_list = Qnil; | |
462 | 2004 |
872 | 2005 #if defined (HAVE_X_WINDOWS) || defined (HAVE_GTK) |
2865 | 2006 |
2367 | 2007 const Ascbyte *fonts[] = |
428 | 2008 { |
872 | 2009 /************** ISO-8859 fonts *************/ |
2010 | |
428 | 2011 "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*", |
1552 | 2012 "-*-fixed-medium-r-*-*-*-120-*-*-*-*-iso8859-*", |
428 | 2013 "-*-courier-*-r-*-*-*-120-*-*-*-*-iso8859-*", |
1552 | 2014 "-*-fixed-*-r-*-*-*-120-*-*-*-*-iso8859-*", |
872 | 2015 /* Next try for any "medium" charcell or monospaced iso8859 font. */ |
428 | 2016 "-*-*-medium-r-*-*-*-120-*-*-m-*-iso8859-*", |
2017 "-*-*-medium-r-*-*-*-120-*-*-c-*-iso8859-*", | |
872 | 2018 /* Next try for any charcell or monospaced iso8859 font. */ |
428 | 2019 "-*-*-*-r-*-*-*-120-*-*-m-*-iso8859-*", |
2020 "-*-*-*-r-*-*-*-120-*-*-c-*-iso8859-*", | |
872 | 2021 |
2022 /* Repeat, any size */ | |
2023 "-*-courier-medium-r-*-*-*-*-*-*-*-*-iso8859-*", | |
1552 | 2024 "-*-fixed-medium-r-*-*-*-*-*-*-*-*-iso8859-*", |
872 | 2025 "-*-courier-*-r-*-*-*-*-*-*-*-*-iso8859-*", |
1552 | 2026 "-*-fixed-*-r-*-*-*-*-*-*-*-*-iso8859-*", |
872 | 2027 /* Next try for any "medium" charcell or monospaced iso8859 font. */ |
2028 "-*-*-medium-r-*-*-*-*-*-*-m-*-iso8859-*", | |
2029 "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-*", | |
2030 /* Next try for any charcell or monospaced iso8859 font. */ | |
2031 "-*-*-*-r-*-*-*-*-*-*-m-*-iso8859-*", | |
2032 "-*-*-*-r-*-*-*-*-*-*-c-*-iso8859-*", | |
2033 | |
2034 /* Non-proportional fonts -- last resort. */ | |
428 | 2035 "-*-*-*-r-*-*-*-120-*-*-*-*-iso8859-*", |
872 | 2036 "-*-*-*-r-*-*-*-*-*-*-*-*-iso8859-*", |
2037 "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*", | |
2038 | |
2039 /************* Japanese fonts ************/ | |
2040 | |
2041 /* Following 3 fonts proposed by Teruhiko.Kurosaka@Japan.eng.sun */ | |
2042 "-sun-gothic-medium-r-normal--14-120-75-75-c-60-jisx0201.1976-0", | |
2043 "-sun-gothic-medium-r-normal--14-120-75-75-c-120-jisx0208.1983-0", | |
2044 "-wadalab-gothic-medium-r-normal--14-120-75-75-c-120-jisx0212.1990-0", | |
2865 | 2045 |
872 | 2046 /* Other Japanese fonts */ |
2047 "-*-fixed-medium-r-*--*-jisx0201.1976-*", | |
2048 "-*-fixed-medium-r-*--*-jisx0208.1983-*", | |
2049 "-*-fixed-medium-r-*--*-jisx0212*-*", | |
2050 "-*-*-*-r-*--*-jisx0201.1976-*", | |
2051 "-*-*-*-r-*--*-jisx0208.1983-*", | |
2052 "-*-*-*-r-*--*-jisx0212*-*", | |
2053 | |
2054 /************* Chinese fonts ************/ | |
2055 | |
2056 "-*-*-medium-r-*--*-gb2312.1980-*", | |
2057 "-*-fixed-medium-r-*--*-cns11643*-*", | |
2865 | 2058 |
872 | 2059 "-*-fixed-medium-r-*--*-big5*-*," |
2060 "-*-fixed-medium-r-*--*-sisheng_cwnn-0", | |
2061 | |
2062 /************* Korean fonts *************/ | |
2063 | |
2064 "-*-mincho-medium-r-*--*-ksc5601.1987-*", | |
2065 | |
2066 /************* Thai fonts **************/ | |
2067 | |
2068 "-*-fixed-medium-r-*--*-tis620.2529-1", | |
2069 | |
2070 /************* Other fonts (nonstandard) *************/ | |
2865 | 2071 |
872 | 2072 "-*-fixed-medium-r-*--*-viscii1.1-1", |
2073 "-*-fixed-medium-r-*--*-mulearabic-*", | |
2074 "-*-fixed-medium-r-*--*-muleipa-*", | |
2075 "-*-fixed-medium-r-*--*-ethio-*", | |
2076 | |
2077 /************* Unicode fonts **************/ | |
2078 | |
2079 /* #### We don't yet support Unicode fonts, but doing so would not be | |
2080 hard because all the machinery has already been added for Windows | |
2081 support. We need to do this: | |
2082 | |
2083 (1) Add "stage 2" support in find_charset_font()/etc.; this finds | |
2084 an appropriate Unicode font after all the charset-specific fonts | |
2085 have been checked. This should look at the per-char font info and | |
2086 check whether we have support for some of the chars in the | |
2087 charset. (#### Bogus, but that's the way it currently works) | |
2088 | |
2089 (2) Record in the font instance a flag indicating when we're | |
2090 dealing with a Unicode font. | |
2091 | |
2092 (3) Notice this flag in separate_textual_runs() and translate the | |
2093 text into Unicode if so. | |
2094 */ | |
2095 | |
2096 "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso10646-1", | |
1552 | 2097 "-*-fixed-medium-r-*-*-*-120-*-*-*-*-iso10646-1", |
872 | 2098 "-*-courier-*-r-*-*-*-120-*-*-*-*-iso10646-1", |
1552 | 2099 "-*-fixed-*-r-*-*-*-120-*-*-*-*-iso10646-1", |
872 | 2100 /* Next try for any "medium" charcell or monospaced iso8859 font. */ |
2101 "-*-*-medium-r-*-*-*-120-*-*-m-*-iso10646-1", | |
2102 "-*-*-medium-r-*-*-*-120-*-*-c-*-iso10646-1", | |
2103 /* Next try for any charcell or monospaced iso8859 font. */ | |
2104 "-*-*-*-r-*-*-*-120-*-*-m-*-iso10646-1", | |
2105 "-*-*-*-r-*-*-*-120-*-*-c-*-iso10646-1", | |
2106 | |
2107 /* Repeat, any size */ | |
2108 "-*-courier-medium-r-*-*-*-*-*-*-*-*-iso10646-1", | |
1552 | 2109 "-*-fixed-medium-r-*-*-*-*-*-*-*-*-iso10646-1", |
872 | 2110 "-*-courier-*-r-*-*-*-*-*-*-*-*-iso10646-1", |
1552 | 2111 "-*-fixed-*-r-*-*-*-*-*-*-*-*-iso10646-1", |
872 | 2112 /* Next try for any "medium" charcell or monospaced iso8859 font. */ |
2113 "-*-*-medium-r-*-*-*-*-*-*-m-*-iso10646-1", | |
2114 "-*-*-medium-r-*-*-*-*-*-*-c-*-iso10646-1", | |
2115 /* Next try for any charcell or monospaced iso8859 font. */ | |
2116 "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1", | |
2117 "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1", | |
2118 | |
2119 /* Non-proportional fonts -- last resort. */ | |
2120 "-*-*-*-r-*-*-*-120-*-*-*-*-iso10646-1", | |
2121 "-*-*-*-r-*-*-*-*-*-*-*-*-iso10646-1", | |
2122 "-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1", | |
2123 | |
2124 /*********** Last resort ***********/ | |
2125 | |
2126 /* Boy, we sure are losing now. Try the above, but in any encoding. */ | |
428 | 2127 "-*-*-medium-r-*-*-*-120-*-*-m-*-*-*", |
2128 "-*-*-medium-r-*-*-*-120-*-*-c-*-*-*", | |
2129 "-*-*-*-r-*-*-*-120-*-*-m-*-*-*", | |
2130 "-*-*-*-r-*-*-*-120-*-*-c-*-*-*", | |
872 | 2131 /* Hello? Please? */ |
428 | 2132 "-*-*-*-r-*-*-*-120-*-*-*-*-*-*", |
2133 "-*-*-*-*-*-*-*-120-*-*-*-*-*-*", | |
872 | 2134 "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", |
428 | 2135 "*" |
2136 }; | |
2367 | 2137 const Ascbyte **fontptr; |
428 | 2138 |
462 | 2139 #ifdef HAVE_X_WINDOWS |
428 | 2140 for (fontptr = fonts + countof(fonts) - 1; fontptr >= fonts; fontptr--) |
2141 inst_list = Fcons (Fcons (list1 (Qx), build_string (*fontptr)), | |
2142 inst_list); | |
2143 #endif /* HAVE_X_WINDOWS */ | |
2144 | |
462 | 2145 #ifdef HAVE_GTK |
2146 for (fontptr = fonts + countof(fonts) - 1; fontptr >= fonts; fontptr--) | |
2147 inst_list = Fcons (Fcons (list1 (Qgtk), build_string (*fontptr)), | |
2148 inst_list); | |
2149 #endif /* HAVE_GTK */ | |
2150 #endif /* HAVE_X_WINDOWS || HAVE_GTK */ | |
2151 | |
428 | 2152 #ifdef HAVE_TTY |
2153 inst_list = Fcons (Fcons (list1 (Qtty), build_string ("normal")), | |
2154 inst_list); | |
2155 #endif /* HAVE_TTY */ | |
440 | 2156 |
771 | 2157 #ifdef HAVE_MS_WINDOWS |
2158 { | |
2367 | 2159 const Ascbyte *mswfonts[] = |
771 | 2160 { |
2161 "Courier New:Regular:10::", | |
2162 "Courier:Regular:10::", | |
2163 ":Regular:10::" | |
2164 }; | |
2367 | 2165 const Ascbyte **mswfontptr; |
2865 | 2166 |
771 | 2167 for (mswfontptr = mswfonts + countof (mswfonts) - 1; |
2168 mswfontptr >= mswfonts; mswfontptr--) | |
2169 { | |
2170 /* display device */ | |
2865 | 2171 inst_list = Fcons (Fcons (list1 (Qmswindows), |
771 | 2172 build_string (*mswfontptr)), |
2173 inst_list); | |
2174 /* printer device */ | |
2865 | 2175 inst_list = Fcons (Fcons (list1 (Qmsprinter), |
771 | 2176 build_string (*mswfontptr)), |
2177 inst_list); | |
2178 } | |
793 | 2179 /* Use Lucida Console rather than Courier New if it exists -- the |
2180 line spacing is much less, so many more lines fit with the same | |
2181 size font. (And it's specifically designed for screens.) */ | |
2865 | 2182 inst_list = Fcons (Fcons (list1 (Qmswindows), |
793 | 2183 build_string ("Lucida Console:Regular:10::")), |
2184 inst_list); | |
771 | 2185 } |
428 | 2186 #endif /* HAVE_MS_WINDOWS */ |
771 | 2187 |
428 | 2188 set_specifier_fallback (Fget (Vdefault_face, Qfont, Qnil), inst_list); |
2189 } | |
2190 | |
2191 set_specifier_fallback (Fget (Vdefault_face, Qunderline, Qnil), | |
2192 list1 (Fcons (Qnil, Qnil))); | |
2193 set_specifier_fallback (Fget (Vdefault_face, Qstrikethru, Qnil), | |
2194 list1 (Fcons (Qnil, Qnil))); | |
2195 set_specifier_fallback (Fget (Vdefault_face, Qhighlight, Qnil), | |
2196 list1 (Fcons (Qnil, Qnil))); | |
2197 set_specifier_fallback (Fget (Vdefault_face, Qdim, Qnil), | |
2198 list1 (Fcons (Qnil, Qnil))); | |
2199 set_specifier_fallback (Fget (Vdefault_face, Qblinking, Qnil), | |
2200 list1 (Fcons (Qnil, Qnil))); | |
2201 set_specifier_fallback (Fget (Vdefault_face, Qreverse, Qnil), | |
2202 list1 (Fcons (Qnil, Qnil))); | |
2203 | |
2204 /* gui-element is the parent face of all gui elements such as | |
2205 modeline, vertical divider and toolbar. */ | |
2206 Vgui_element_face = Fmake_face (Qgui_element, | |
771 | 2207 build_msg_string ("gui element face"), |
428 | 2208 Qnil); |
2209 | |
2210 /* Provide some last-resort fallbacks for gui-element face which | |
2211 mustn't default to default. */ | |
2212 { | |
2213 Lisp_Object fg_fb = Qnil, bg_fb = Qnil; | |
2214 | |
462 | 2215 #ifdef HAVE_GTK |
2216 /* We need to put something in there, or error checking gets | |
2217 #%!@#ed up before the styles are set, which override the | |
2218 fallbacks. */ | |
2219 fg_fb = acons (list1 (Qgtk), build_string ("black"), fg_fb); | |
2220 bg_fb = acons (list1 (Qgtk), build_string ("Gray80"), bg_fb); | |
2221 #endif | |
428 | 2222 #ifdef HAVE_X_WINDOWS |
2223 fg_fb = acons (list1 (Qx), build_string ("black"), fg_fb); | |
2224 bg_fb = acons (list1 (Qx), build_string ("Gray80"), bg_fb); | |
2225 #endif | |
2226 #ifdef HAVE_TTY | |
2227 fg_fb = acons (list1 (Qtty), Fvector (0, 0), fg_fb); | |
2228 bg_fb = acons (list1 (Qtty), Fvector (0, 0), bg_fb); | |
2229 #endif | |
2230 #ifdef HAVE_MS_WINDOWS | |
440 | 2231 fg_fb = acons (list1 (Qmsprinter), build_string ("black"), fg_fb); |
2232 bg_fb = acons (list1 (Qmsprinter), build_string ("white"), bg_fb); | |
428 | 2233 fg_fb = acons (list1 (Qmswindows), build_string ("black"), fg_fb); |
2234 bg_fb = acons (list1 (Qmswindows), build_string ("Gray75"), bg_fb); | |
2235 #endif | |
2236 set_specifier_fallback (Fget (Vgui_element_face, Qforeground, Qnil), fg_fb); | |
2237 set_specifier_fallback (Fget (Vgui_element_face, Qbackground, Qnil), bg_fb); | |
2238 } | |
2239 | |
2240 /* Now create the other faces that redisplay needs to refer to | |
2241 directly. We could create them in Lisp but it's simpler this | |
2242 way since we need to get them anyway. */ | |
2243 | |
2244 /* modeline is gui element. */ | |
771 | 2245 Vmodeline_face = Fmake_face (Qmodeline, build_msg_string ("modeline face"), |
428 | 2246 Qnil); |
2247 | |
2248 set_specifier_fallback (Fget (Vmodeline_face, Qforeground, Qunbound), | |
2249 Fget (Vgui_element_face, Qforeground, Qunbound)); | |
2250 set_specifier_fallback (Fget (Vmodeline_face, Qbackground, Qunbound), | |
2251 Fget (Vgui_element_face, Qbackground, Qunbound)); | |
2252 set_specifier_fallback (Fget (Vmodeline_face, Qbackground_pixmap, Qnil), | |
2253 Fget (Vgui_element_face, Qbackground_pixmap, | |
2254 Qunbound)); | |
2255 | |
2256 /* toolbar is another gui element */ | |
2257 Vtoolbar_face = Fmake_face (Qtoolbar, | |
771 | 2258 build_msg_string ("toolbar face"), |
428 | 2259 Qnil); |
2260 set_specifier_fallback (Fget (Vtoolbar_face, Qforeground, Qunbound), | |
2261 Fget (Vgui_element_face, Qforeground, Qunbound)); | |
2262 set_specifier_fallback (Fget (Vtoolbar_face, Qbackground, Qunbound), | |
2263 Fget (Vgui_element_face, Qbackground, Qunbound)); | |
2264 set_specifier_fallback (Fget (Vtoolbar_face, Qbackground_pixmap, Qnil), | |
2265 Fget (Vgui_element_face, Qbackground_pixmap, | |
2266 Qunbound)); | |
2267 | |
2268 /* vertical divider is another gui element */ | |
2269 Vvertical_divider_face = Fmake_face (Qvertical_divider, | |
771 | 2270 build_msg_string ("vertical divider face"), |
428 | 2271 Qnil); |
2272 | |
2273 set_specifier_fallback (Fget (Vvertical_divider_face, Qforeground, Qunbound), | |
2274 Fget (Vgui_element_face, Qforeground, Qunbound)); | |
2275 set_specifier_fallback (Fget (Vvertical_divider_face, Qbackground, Qunbound), | |
2276 Fget (Vgui_element_face, Qbackground, Qunbound)); | |
2277 set_specifier_fallback (Fget (Vvertical_divider_face, Qbackground_pixmap, | |
2278 Qunbound), | |
2279 Fget (Vgui_element_face, Qbackground_pixmap, | |
2280 Qunbound)); | |
2281 | |
2282 /* widget is another gui element */ | |
2283 Vwidget_face = Fmake_face (Qwidget, | |
771 | 2284 build_msg_string ("widget face"), |
428 | 2285 Qnil); |
442 | 2286 set_specifier_fallback (Fget (Vwidget_face, Qfont, Qunbound), |
2287 Fget (Vgui_element_face, Qfont, Qunbound)); | |
428 | 2288 set_specifier_fallback (Fget (Vwidget_face, Qforeground, Qunbound), |
2289 Fget (Vgui_element_face, Qforeground, Qunbound)); | |
2290 set_specifier_fallback (Fget (Vwidget_face, Qbackground, Qunbound), | |
2291 Fget (Vgui_element_face, Qbackground, Qunbound)); | |
442 | 2292 /* We don't want widgets to have a default background pixmap. */ |
428 | 2293 |
2294 Vleft_margin_face = Fmake_face (Qleft_margin, | |
771 | 2295 build_msg_string ("left margin face"), |
428 | 2296 Qnil); |
2297 Vright_margin_face = Fmake_face (Qright_margin, | |
771 | 2298 build_msg_string ("right margin face"), |
428 | 2299 Qnil); |
2300 Vtext_cursor_face = Fmake_face (Qtext_cursor, | |
771 | 2301 build_msg_string ("face for text cursor"), |
428 | 2302 Qnil); |
2303 Vpointer_face = | |
2304 Fmake_face (Qpointer, | |
771 | 2305 build_msg_string |
428 | 2306 ("face for foreground/background colors of mouse pointer"), |
2307 Qnil); | |
2308 } |