comparison src/specifier.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 /* Specifier implementation
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995, 1996 Ben Wing.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23 /* Synched up with: Not in FSF. */
24
25 /* Design by Ben Wing;
26 Original version by Chuck Thompson;
27 rewritten by Ben Wing */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "device.h"
34 #include "frame.h"
35 #include "opaque.h"
36 #include "specifier.h"
37 #include "window.h"
38
39 Lisp_Object Qspecifierp;
40 Lisp_Object Qprepend, Qappend, Qremove_tag_set_prepend, Qremove_tag_set_append;
41 Lisp_Object Qremove_locale, Qremove_locale_type, Qremove_all;
42 Lisp_Object Qfallback;
43
44 /* Qinteger, Qboolean, Qgeneric defined in general.c. */
45 Lisp_Object Qnatnum;
46
47 Lisp_Object Qconsole_type, Qdevice_class;
48
49 Lisp_Object Vuser_defined_tags;
50
51 MAC_DEFINE (struct Lisp_Specifier *, MTspecmeth_or_given)
52 MAC_DEFINE (struct Lisp_Specifier *, MTspecifier_data)
53
54 struct specifier_type_entry
55 {
56 Lisp_Object symbol;
57 struct specifier_methods *meths;
58 };
59
60 typedef struct specifier_type_entry_dynarr_type
61 {
62 Dynarr_declare (struct specifier_type_entry);
63 } specifier_type_entry_dynarr;
64
65 specifier_type_entry_dynarr *the_specifier_type_entry_dynarr;
66
67 Lisp_Object Vspecifier_type_list;
68
69 Lisp_Object Vcached_specifiers;
70 /* Do NOT mark through this, or specifiers will never be GC'd. */
71 Lisp_Object Vall_specifiers;
72
73 /* #### The purpose of this is to check for inheritance loops
74 in specifiers that can inherit from other specifiers, but it's
75 not yet implemented.
76
77 #### Look into this for 19.14. */
78 lisp_dynarr current_specifiers;
79
80 static void recompute_cached_specifier_everywhere (Lisp_Object specifier);
81
82
83 /************************************************************************/
84 /* Specifier object methods */
85 /************************************************************************/
86
87 static Lisp_Object mark_specifier (Lisp_Object, void (*) (Lisp_Object));
88 static void print_specifier (Lisp_Object, Lisp_Object, int);
89 static int specifier_equal (Lisp_Object, Lisp_Object, int depth);
90 static unsigned long specifier_hash (Lisp_Object obj, int depth);
91 static unsigned int sizeof_specifier (CONST void *header);
92 static void finalize_specifier (void *header, int for_disksave);
93 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("specifier", specifier,
94 mark_specifier, print_specifier,
95 finalize_specifier,
96 specifier_equal, specifier_hash,
97 sizeof_specifier,
98 struct Lisp_Specifier);
99
100 /* Remove dead objects from the specified assoc list. */
101
102 static Lisp_Object
103 cleanup_assoc_list (Lisp_Object list)
104 {
105 Lisp_Object loop, prev, retval;
106
107 loop = retval = list;
108 prev = Qnil;
109
110 while (!NILP (loop))
111 {
112 Lisp_Object entry = XCAR (loop);
113 Lisp_Object key = XCAR (entry);
114
115 /* remember, dead windows can become alive again. */
116 if (!WINDOWP (key) && object_dead_p (key))
117 {
118 if (NILP (prev))
119 {
120 /* Removing the head. */
121 retval = XCDR (retval);
122 }
123 else
124 {
125 Fsetcdr (prev, XCDR (loop));
126 }
127 }
128 else
129 prev = loop;
130
131 loop = XCDR (loop);
132 }
133
134 return retval;
135 }
136
137 /* Remove dead objects from the various lists so that they
138 don't keep getting marked as long as this specifier exists and
139 therefore wasting memory. */
140
141 void
142 cleanup_specifiers (void)
143 {
144 Lisp_Object rest;
145
146 for (rest = Vall_specifiers;
147 !NILP (rest);
148 rest = XSPECIFIER (rest)->next_specifier)
149 {
150 struct Lisp_Specifier *sp = XSPECIFIER (rest);
151 /* This effectively changes the specifier specs.
152 However, there's no need to call
153 recompute_cached_specifier_everywhere() or the
154 after-change methods because the only specs we
155 are removing are for dead objects, and they can
156 never have any effect on the specifier values:
157 specifiers can only be instantiated over live
158 objects, and you can't derive a dead object
159 from a live one. */
160 sp->device_specs = cleanup_assoc_list (sp->device_specs);
161 sp->frame_specs = cleanup_assoc_list (sp->frame_specs);
162 sp->buffer_specs = cleanup_assoc_list (sp->buffer_specs);
163 /* windows are handled specially because dead windows
164 can be resurrected */
165 }
166 }
167
168 void
169 kill_specifier_buffer_locals (Lisp_Object buffer)
170 {
171 Lisp_Object rest;
172
173 for (rest = Vall_specifiers;
174 !NILP (rest);
175 rest = XSPECIFIER (rest)->next_specifier)
176 {
177 struct Lisp_Specifier *sp = XSPECIFIER (rest);
178
179 /* Make sure we're actually going to be changing something.
180 Fremove_specifier() always calls
181 recompute_cached_specifier_everywhere() (#### but should
182 be smarter about this). */
183 if (!NILP (assq_no_quit (buffer, sp->buffer_specs)))
184 Fremove_specifier (rest, buffer, Qnil, Qnil);
185 }
186 }
187
188 static Lisp_Object
189 mark_specifier (Lisp_Object obj, void (*markobj) (Lisp_Object))
190 {
191 struct Lisp_Specifier *specifier = XSPECIFIER (obj);
192
193 ((markobj) (specifier->global_specs));
194 ((markobj) (specifier->device_specs));
195 ((markobj) (specifier->frame_specs));
196 ((markobj) (specifier->window_specs));
197 ((markobj) (specifier->buffer_specs));
198 ((markobj) (specifier->fallback));
199 MAYBE_SPECMETH (specifier, mark, (obj, markobj));
200 return Qnil;
201 }
202
203 /* The idea here is that the specifier specs point to locales
204 (windows, buffers, frames, and devices), and we want to make sure
205 that the specs disappear automatically when the associated locale
206 is no longer in use. For all but windows, "no longer in use"
207 corresponds exactly to when the object is deleted (non-deleted
208 objects are always held permanently in special lists, and deleted
209 objects are never on these lists and never reusable). To handle
210 this, we just have cleanup_specifiers() called periodically
211 (at the beginning of garbage collection); it removes all dead
212 objects.
213
214 For windows, however, it's trickier because dead objects can be
215 converted to live ones again if the dead object is in a window
216 configuration. Therefore, for windows, "no longer in use"
217 corresponds to when the window object is garbage-collected.
218 We now use weak lists for this purpose.
219
220 */
221
222 void
223 prune_specifiers (int (*obj_marked_p) (Lisp_Object))
224 {
225 Lisp_Object rest, prev = Qnil;
226
227 for (rest = Vall_specifiers;
228 !GC_NILP (rest);
229 rest = XSPECIFIER (rest)->next_specifier)
230 {
231 if (! ((*obj_marked_p) (rest)))
232 {
233 /* This specifier is garbage. Remove it from the list. */
234 if (GC_NILP (prev))
235 Vall_specifiers = XSPECIFIER (rest)->next_specifier;
236 else
237 XSPECIFIER (prev)->next_specifier =
238 XSPECIFIER (rest)->next_specifier;
239 }
240 }
241 }
242
243 static void
244 print_specifier (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
245 {
246 struct Lisp_Specifier *sp = XSPECIFIER (obj);
247 char buf[100];
248 int count = specpdl_depth ();
249 Lisp_Object the_specs;
250
251 if (print_readably)
252 error ("printing unreadable object #<%s-specifier 0x%x>",
253 sp->methods->name, sp->header.uid);
254
255 sprintf (buf, "#<%s-specifier global=", sp->methods->name);
256 write_c_string (buf, printcharfun);
257 specbind (Qprint_string_length, make_int (100));
258 specbind (Qprint_length, make_int (5));
259 the_specs = Fspecifier_specs (obj, Qglobal, Qnil, Qnil);
260 if (NILP (the_specs))
261 /* there are no global specs */
262 write_c_string ("<unspecified>", printcharfun);
263 else
264 print_internal (the_specs, printcharfun, 1);
265 if (!NILP (sp->fallback))
266 {
267 write_c_string (" fallback=", printcharfun);
268 print_internal (sp->fallback, printcharfun, escapeflag);
269 }
270 unbind_to (count, Qnil);
271 sprintf (buf, " 0x%x>", sp->header.uid);
272 write_c_string (buf, printcharfun);
273 }
274
275 static void
276 finalize_specifier (void *header, int for_disksave)
277 {
278 struct Lisp_Specifier *sp = (struct Lisp_Specifier *) header;
279 /* don't be snafued by the disksave finalization. */
280 if (!for_disksave && sp->caching)
281 {
282 xfree (sp->caching);
283 sp->caching = 0;
284 }
285 }
286
287 static int
288 specifier_equal (Lisp_Object o1, Lisp_Object o2, int depth)
289 {
290 struct Lisp_Specifier *s1 = XSPECIFIER (o1);
291 struct Lisp_Specifier *s2 = XSPECIFIER (o2);
292 int retval;
293 Lisp_Object old_inhibit_quit = Vinhibit_quit;
294
295 /* This function can be called from within redisplay.
296 internal_equal can trigger a quit. That leads to Bad Things. */
297 Vinhibit_quit = Qt;
298
299 depth++;
300 if (s1->methods != s2->methods ||
301 !internal_equal (s1->global_specs, s2->global_specs, depth) ||
302 !internal_equal (s1->device_specs, s2->device_specs, depth) ||
303 !internal_equal (s1->frame_specs, s2->frame_specs, depth) ||
304 !internal_equal (s1->window_specs, s2->window_specs, depth) ||
305 !internal_equal (s1->buffer_specs, s2->buffer_specs, depth) ||
306 !SPECMETH_OR_GIVEN (s1, equal, (o1, o2, depth - 1), 1))
307 retval = 0;
308 else
309 retval = 1;
310
311 Vinhibit_quit = old_inhibit_quit;
312 return retval;
313 }
314
315 static unsigned long
316 specifier_hash (Lisp_Object obj, int depth)
317 {
318 struct Lisp_Specifier *s = XSPECIFIER (obj);
319
320 /* specifier hashing is a bit problematic because there are so
321 many places where data can be stored. We pick what are perhaps
322 the most likely places where interesting stuff will be. */
323 return HASH5 (SPECMETH_OR_GIVEN (s, hash, (obj, depth), 0),
324 (unsigned long) s->methods,
325 internal_hash (s->global_specs, depth + 1),
326 internal_hash (s->frame_specs, depth + 1),
327 internal_hash (s->buffer_specs, depth + 1));
328 }
329
330 static unsigned int
331 sizeof_specifier (CONST void *header)
332 {
333 CONST struct Lisp_Specifier *p = (CONST struct Lisp_Specifier *) header;
334 return sizeof (*p) + p->methods->extra_data_size - 1;
335 }
336
337
338 /************************************************************************/
339 /* Creating specifiers */
340 /************************************************************************/
341
342 static struct specifier_methods *
343 decode_specifier_type (Lisp_Object type, Error_behavior errb)
344 {
345 int i;
346
347 for (i = 0; i < Dynarr_length (the_specifier_type_entry_dynarr); i++)
348 {
349 if (EQ (type, Dynarr_at (the_specifier_type_entry_dynarr, i).symbol))
350 return Dynarr_at (the_specifier_type_entry_dynarr, i).meths;
351 }
352
353 maybe_signal_simple_error ("Invalid specifier type", type,
354 Qspecifier, errb);
355
356 return 0;
357 }
358
359 static int
360 valid_specifier_type_p (Lisp_Object type)
361 {
362 if (decode_specifier_type (type, ERROR_ME_NOT))
363 return 1;
364 return 0;
365 }
366
367 DEFUN ("valid-specifier-type-p", Fvalid_specifier_type_p,
368 Svalid_specifier_type_p, 1, 1, 0 /*
369 Given a SPECIFIER-TYPE, return non-nil if it is valid.
370 Valid types are 'generic, 'integer, boolean, 'color, 'font, 'image,
371 'face-boolean, and 'toolbar.
372 */ )
373 (specifier_type)
374 Lisp_Object specifier_type;
375 {
376 if (valid_specifier_type_p (specifier_type))
377 return Qt;
378 else
379 return Qnil;
380 }
381
382 DEFUN ("specifier-type-list", Fspecifier_type_list, Sspecifier_type_list,
383 0, 0, 0 /*
384 Return a list of valid specifier types.
385 */ )
386 ()
387 {
388 return Fcopy_sequence (Vspecifier_type_list);
389 }
390
391 void
392 add_entry_to_specifier_type_list (Lisp_Object symbol,
393 struct specifier_methods *meths)
394 {
395 struct specifier_type_entry entry;
396
397 entry.symbol = symbol;
398 entry.meths = meths;
399 Dynarr_add (the_specifier_type_entry_dynarr, entry);
400 Vspecifier_type_list = Fcons (symbol, Vspecifier_type_list);
401 }
402
403 static Lisp_Object
404 make_specifier (struct specifier_methods *spec_meths)
405 {
406 struct Lisp_Specifier *sp;
407 Lisp_Object specifier = Qnil;
408 struct gcpro gcpro1;
409
410 sp = alloc_lcrecord (sizeof (struct Lisp_Specifier) +
411 spec_meths->extra_data_size - 1, lrecord_specifier);
412
413 sp->methods = spec_meths;
414 sp->global_specs = Qnil;
415 sp->device_specs = Qnil;
416 sp->frame_specs = Qnil;
417 sp->window_specs = make_weak_list (WEAK_LIST_KEY_ASSOC);
418 sp->buffer_specs = Qnil;
419 sp->fallback = Qnil;
420 sp->caching = 0;
421 sp->next_specifier = Vall_specifiers;
422
423 XSETSPECIFIER (specifier, sp);
424 Vall_specifiers = specifier;
425
426 GCPRO1 (specifier);
427 MAYBE_SPECMETH (XSPECIFIER (specifier), create, (specifier));
428 UNGCPRO;
429 return specifier;
430 }
431
432 DEFUN ("make-specifier", Fmake_specifier, Smake_specifier, 1, 1, 0 /*
433 Create a new specifier.
434
435 A specifier is an object that can be used to keep track of a property
436 whose value can be per-buffer, per-window, per-frame, or per-device,
437 and can further be restricted to a particular console-type or device-class.
438 Specifiers are used, for example, for the various built-in properties of a
439 face; this allows a face to have different values in different frames,
440 buffers, etc. For more information, see `specifier-instance',
441 `specifier-specs', and `add-spec-to-specifier'; or, for a detailed
442 description of specifiers, including how they are instantiated over a
443 particular domain (i.e. how their value in that domain is determined),
444 see the chapter on specifiers in the XEmacs Lisp Reference Manual.
445
446 TYPE specifies the particular type of specifier, and should be one of
447 the symbols 'generic, 'integer, 'boolean, 'color, 'font, 'image,
448 'face-boolean, or 'toolbar.
449
450 For more information on particular types of specifiers, see the functions
451 `generic-specifier-p', `integer-specifier-p', `boolean-specifier-p',
452 `color-specifier-p', `font-specifier-p', `image-specifier-p',
453 `face-boolean-specifier-p', and `toolbar-specifier-p'.
454 */ )
455 (type)
456 Lisp_Object type;
457 {
458 /* This function can GC */
459 struct specifier_methods *meths = decode_specifier_type (type,
460 ERROR_ME);
461
462 return make_specifier (meths);
463 }
464
465 DEFUN ("specifierp", Fspecifierp, Sspecifierp, 1, 1, 0 /*
466 Return non-nil if OBJECT is a specifier.
467
468 A specifier is an object that can be used to keep track of a property
469 whose value can be per-buffer, per-window, per-frame, or per-device,
470 and can further be restricted to a particular console-type or device-class.
471 See `make-specifier'.
472 */ )
473 (object)
474 Lisp_Object object;
475 {
476 if (!SPECIFIERP (object))
477 return Qnil;
478 return Qt;
479 }
480
481 DEFUN ("specifier-type", Fspecifier_type, Sspecifier_type, 1, 1, 0 /*
482 Return the type of SPECIFIER.
483 */ )
484 (specifier)
485 Lisp_Object specifier;
486 {
487 CHECK_SPECIFIER (specifier);
488 return intern (XSPECIFIER (specifier)->methods->name);
489 }
490
491
492 /************************************************************************/
493 /* Locales and domains */
494 /************************************************************************/
495
496 DEFUN ("valid-specifier-locale-p", Fvalid_specifier_locale_p,
497 Svalid_specifier_locale_p, 1, 1, 0 /*
498 Return non-nil if LOCALE is a valid specifier locale.
499 Valid locales are a device, a frame, a window, a buffer, and 'global.
500 (nil is not valid.)
501 */ )
502 (locale)
503 Lisp_Object locale;
504 {
505 /* This cannot GC. */
506 if ((DEVICEP (locale) && DEVICE_LIVE_P (XDEVICE (locale))) ||
507 (FRAMEP (locale) && FRAME_LIVE_P (XFRAME (locale))) ||
508 (BUFFERP (locale) && BUFFER_LIVE_P (XBUFFER (locale))) ||
509 /* dead windows are allowed because they may become live
510 windows again when a window configuration is restored */
511 WINDOWP (locale) ||
512 EQ (locale, Qglobal))
513 return Qt;
514 else
515 return Qnil;
516 }
517
518 DEFUN ("valid-specifier-domain-p",
519 Fvalid_specifier_domain_p,
520 Svalid_specifier_domain_p, 1, 1, 0 /*
521 Return non-nil if DOMAIN is a valid specifier domain.
522 A domain is used to instance a specifier (i.e. determine the specifier's
523 value in that domain). Valid domains are a window, frame, or device.
524 (nil is not valid.)
525 */ )
526 (domain)
527 Lisp_Object domain;
528 {
529 /* This cannot GC. */
530 if ((DEVICEP (domain) && DEVICE_LIVE_P (XDEVICE (domain))) ||
531 (FRAMEP (domain) && FRAME_LIVE_P (XFRAME (domain))) ||
532 (WINDOWP (domain) && WINDOW_LIVE_P (XWINDOW (domain))))
533 return Qt;
534 else
535 return Qnil;
536 }
537
538 DEFUN ("valid-specifier-locale-type-p",
539 Fvalid_specifier_locale_type_p,
540 Svalid_specifier_locale_type_p, 1, 1, 0 /*
541 Given a specifier LOCALE-TYPE, return non-nil if it is valid.
542 Valid locale types are 'global, 'device, 'frame, 'window, and 'buffer.
543 (Note, however, that in functions that accept either a locale or a locale
544 type, 'global is considered an individual locale.)
545 */ )
546 (locale_type)
547 Lisp_Object locale_type;
548 {
549 /* This cannot GC. */
550 if (EQ (locale_type, Qglobal) ||
551 EQ (locale_type, Qdevice) ||
552 EQ (locale_type, Qframe) ||
553 EQ (locale_type, Qwindow) ||
554 EQ (locale_type, Qbuffer))
555 return Qt;
556 else
557 return Qnil;
558 }
559
560 static void
561 check_valid_locale_or_locale_type (Lisp_Object locale)
562 {
563 /* This cannot GC. */
564 if (EQ (locale, Qall) ||
565 !NILP (Fvalid_specifier_locale_p (locale)) ||
566 !NILP (Fvalid_specifier_locale_type_p (locale)))
567 return;
568 signal_simple_error ("Invalid specifier locale or locale type", locale);
569 }
570
571 DEFUN ("specifier-locale-type-from-locale",
572 Fspecifier_locale_type_from_locale,
573 Sspecifier_locale_type_from_locale, 1, 1, 0 /*
574 Given a specifier LOCALE, return its type.
575 */ )
576 (locale)
577 Lisp_Object locale;
578 {
579 /* This cannot GC. */
580 if (NILP (Fvalid_specifier_locale_p (locale)))
581 signal_simple_error ("Invalid specifier locale", locale);
582 if (DEVICEP (locale))
583 return Qdevice;
584 if (FRAMEP (locale))
585 return Qframe;
586 if (WINDOWP (locale))
587 return Qwindow;
588 if (BUFFERP (locale))
589 return Qbuffer;
590 assert (EQ (locale, Qglobal));
591 return Qglobal;
592 }
593
594 Lisp_Object
595 decode_locale (Lisp_Object locale)
596 {
597 /* This cannot GC. */
598 if (NILP (locale))
599 return Qglobal;
600 else if (!NILP (Fvalid_specifier_locale_p (locale)))
601 return locale;
602 else
603 signal_simple_error ("Invalid specifier locale", locale);
604
605 return Qnil;
606 }
607
608 static enum spec_locale_type
609 decode_locale_type (Lisp_Object locale_type)
610 {
611 /* This cannot GC. */
612 if (EQ (locale_type, Qglobal))
613 return LOCALE_GLOBAL;
614 if (EQ (locale_type, Qdevice))
615 return LOCALE_DEVICE;
616 if (EQ (locale_type, Qframe))
617 return LOCALE_FRAME;
618 if (EQ (locale_type, Qwindow))
619 return LOCALE_WINDOW;
620 if (EQ (locale_type, Qbuffer))
621 return LOCALE_BUFFER;
622 signal_simple_error ("Invalid specifier locale type", locale_type);
623 return 0;
624 }
625
626 Lisp_Object
627 decode_locale_list (Lisp_Object locale)
628 {
629 /* This cannot GC. */
630 /* The return value of this function must be GCPRO'd. */
631 if (NILP (locale))
632 locale = list1 (Qall);
633 else
634 {
635 Lisp_Object rest;
636 if (!CONSP (locale))
637 locale = list1 (locale);
638 EXTERNAL_LIST_LOOP (rest, locale)
639 check_valid_locale_or_locale_type (XCAR (rest));
640 }
641 return locale;
642 }
643
644 static enum spec_locale_type
645 locale_type_from_locale (Lisp_Object locale)
646 {
647 return decode_locale_type (Fspecifier_locale_type_from_locale (locale));
648 }
649
650 static void
651 check_valid_domain (Lisp_Object domain)
652 {
653 if (NILP (Fvalid_specifier_domain_p (domain)))
654 signal_simple_error ("Invalid specifier domain", domain);
655 }
656
657 Lisp_Object
658 decode_domain (Lisp_Object domain)
659 {
660 if (NILP (domain))
661 return Fselected_window (Qnil);
662 check_valid_domain (domain);
663 return domain;
664 }
665
666
667 /************************************************************************/
668 /* Tags */
669 /************************************************************************/
670
671 DEFUN ("valid-specifier-tag-p", Fvalid_specifier_tag_p,
672 Svalid_specifier_tag_p,
673 1, 1, 0 /*
674 Return non-nil if TAG is a valid specifier tag.
675 See also `valid-specifier-tag-set-p'.
676 */ )
677 (tag)
678 Lisp_Object tag;
679 {
680 if (valid_console_type_p (tag) ||
681 valid_device_class_p (tag) ||
682 !NILP (assq_no_quit (tag, Vuser_defined_tags)))
683 return Qt;
684 return Qnil;
685 }
686
687 DEFUN ("valid-specifier-tag-set-p", Fvalid_specifier_tag_set_p,
688 Svalid_specifier_tag_set_p,
689 1, 1, 0 /*
690 Return non-nil if TAG-SET is a valid specifier tag set.
691
692 A specifier tag set is an entity that is attached to an instantiator
693 and can be used to restrict the scope of that instantiator to a
694 particular device class or device type and/or to mark instantiators
695 added by a particular package so that they can be later removed.
696
697 A specifier tag set consists of a list of zero of more specifier tags,
698 each of which is a symbol that is recognized by XEmacs as a tag.
699 (The valid device types and device classes are always tags, as are
700 any tags defined by `define-specifier-tag'.) It is called a \"tag set\"
701 (as opposed to a list) because the order of the tags or the number of
702 times a particular tag occurs does not matter.
703
704 Each tag has a predicate associated with it, which specifies whether
705 that tag applies to a particular device. The tags which are device types
706 and classes match devices of that type or class. User-defined tags can
707 have any predicate, or none (meaning that all devices match). When
708 attempting to instance a specifier, a particular instantiator is only
709 considered if the device of the domain being instanced over matches
710 all tags in the tag set attached to that instantiator.
711
712 Most of the time, a tag set is not specified, and the instantiator
713 gets a null tag set, which matches all devices.
714 */ )
715 (tag_set)
716 Lisp_Object tag_set;
717 {
718 Lisp_Object rest;
719
720 for (rest = tag_set; !NILP (rest); rest = XCDR (rest))
721 {
722 if (!CONSP (rest))
723 return Qnil;
724 if (NILP (Fvalid_specifier_tag_p (XCAR (rest))))
725 return Qnil;
726 QUIT;
727 }
728 return Qt;
729 }
730
731 Lisp_Object
732 decode_specifier_tag_set (Lisp_Object tag_set)
733 {
734 /* The return value of this function must be GCPRO'd. */
735 if (!NILP (Fvalid_specifier_tag_p (tag_set)))
736 return list1 (tag_set);
737 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
738 signal_simple_error ("Invalid specifier tag-set", tag_set);
739 return tag_set;
740 }
741
742 static Lisp_Object
743 canonicalize_tag_set (Lisp_Object tag_set)
744 {
745 int len = XINT (Flength (tag_set));
746 Lisp_Object *tags, rest;
747 int i, j;
748
749 /* We assume in this function that the tag_set has already been
750 validated, so there are no surprises. */
751
752 if (len == 0 || len == 1)
753 /* most common case */
754 return tag_set;
755
756 tags = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
757
758 i = 0;
759 LIST_LOOP (rest, tag_set)
760 tags[i++] = XCAR (rest);
761
762 /* Sort the list of tags. We use a bubble sort here (copied from
763 extent_fragment_update()) -- reduces the function call overhead,
764 and is the fastest sort for small numbers of items. */
765
766 for (i = 1; i < len; i++)
767 {
768 j = i - 1;
769 while (j >= 0 &&
770 strcmp ((char *) string_data (XSYMBOL (tags[j])->name),
771 (char *) string_data (XSYMBOL (tags[j+1])->name)) > 0)
772 {
773 Lisp_Object tmp = tags[j];
774 tags[j] = tags[j+1];
775 tags[j+1] = tmp;
776 j--;
777 }
778 }
779
780 /* Now eliminate duplicates. */
781
782 for (i = 1, j = 1; i < len; i++)
783 {
784 /* j holds the destination, i the source. */
785 if (!EQ (tags[i], tags[i-1]))
786 tags[j++] = tags[i];
787 }
788
789 return Flist (j, tags);
790 }
791
792 DEFUN ("canonicalize-tag-set", Fcanonicalize_tag_set,
793 Scanonicalize_tag_set, 1, 1, 0 /*
794 Canonicalize the given tag set.
795 Two canonicalized tag sets can be compared with `equal' to see if they
796 represent the same tag set. (Specifically, canonicalizing involves
797 sorting by symbol name and removing duplicates.)
798 */ )
799 (tag_set)
800 Lisp_Object tag_set;
801 {
802 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
803 signal_simple_error ("Invalid tag set", tag_set);
804 return canonicalize_tag_set (tag_set);
805 }
806
807 static int
808 device_matches_specifier_tag_set_p (Lisp_Object device, Lisp_Object tag_set)
809 {
810 Lisp_Object devtype, devclass, rest;
811 struct device *d = XDEVICE (device);
812
813 devtype = DEVICE_TYPE (d);
814 devclass = DEVICE_CLASS (d);
815
816 LIST_LOOP (rest, tag_set)
817 {
818 Lisp_Object tag = XCAR (rest);
819 Lisp_Object assoc;
820
821 if (EQ (tag, devtype) || EQ (tag, devclass))
822 continue;
823 assoc = assq_no_quit (tag, DEVICE_USER_DEFINED_TAGS (d));
824 /* other built-in tags (device types/classes) are not in
825 the user-defined-tags list. */
826 if (NILP (assoc) || NILP (XCDR (assoc)))
827 return 0;
828 }
829
830 return 1;
831 }
832
833 DEFUN ("device-matches-specifier-tag-set-p",
834 Fdevice_matches_specifier_tag_set_p,
835 Sdevice_matches_specifier_tag_set_p,
836 2, 2, 0 /*
837 Return non-nil if DEVICE matches specifier tag set TAG-SET.
838 This means that DEVICE matches each tag in the tag set. (Every
839 tag recognized by XEmacs has a predicate associated with it that
840 specifies which devices match it.)
841 */ )
842 (device, tag_set)
843 Lisp_Object device, tag_set;
844 {
845 CHECK_LIVE_DEVICE (device);
846
847 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
848 signal_simple_error ("Invalid tag set", tag_set);
849
850 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil;
851 }
852
853 DEFUN ("define-specifier-tag", Fdefine_specifier_tag, Sdefine_specifier_tag,
854 1, 2, 0 /*
855 Define a new specifier tag.
856 If PREDICATE is specified, it should be a function of one argument
857 (a device) that specifies whether the tag matches that particular
858 device. If PREDICATE is omitted, the tag matches all devices.
859
860 You can redefine an existing user-defined specifier tag. However,
861 you cannot redefine the built-in specifier tags (the device types
862 and classes) or the symbols nil, t, 'all, or 'global.
863 */ )
864 (tag, predicate)
865 Lisp_Object tag, predicate;
866 {
867 Lisp_Object assoc, devcons, concons;
868 int recompute = 0;
869
870 CHECK_SYMBOL (tag);
871 if (valid_device_class_p (tag) ||
872 valid_console_type_p (tag))
873 signal_simple_error ("Cannot redefine built-in specifier tags", tag);
874 /* Try to prevent common instantiators and locales from being
875 redefined, to reduce ambiguity */
876 if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal))
877 signal_simple_error ("Cannot define nil, t, 'all, or 'global",
878 tag);
879 assoc = assq_no_quit (tag, Vuser_defined_tags);
880 if (NILP (assoc))
881 {
882 recompute = 1;
883 Vuser_defined_tags = Fcons (Fcons (tag, predicate), Vuser_defined_tags);
884 DEVICE_LOOP_NO_BREAK (devcons, concons)
885 {
886 struct device *d = XDEVICE (XCAR (devcons));
887 /* Initially set the value to t in case of error
888 in predicate */
889 DEVICE_USER_DEFINED_TAGS (d) =
890 Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d));
891 }
892 }
893 else if (!NILP (predicate) && !NILP (XCDR (assoc)))
894 {
895 recompute = 1;
896 XCDR (assoc) = predicate;
897 }
898
899 /* recompute the tag values for all devices. However, in the special
900 case where both the old and new predicates are nil, we know that
901 we don't have to do this. (It's probably common for people to
902 call (define-specifier-tag) more than once on the same tag,
903 and the most common case is where PREDICATE is not specified.) */
904
905 if (recompute)
906 {
907 DEVICE_LOOP_NO_BREAK (devcons, concons)
908 {
909 Lisp_Object device = XCAR (devcons);
910 assoc = assq_no_quit (tag,
911 DEVICE_USER_DEFINED_TAGS (XDEVICE (device)));
912 assert (CONSP (assoc));
913 if (NILP (predicate))
914 XCDR (assoc) = Qt;
915 else
916 XCDR (assoc) = !NILP (call1 (predicate, device)) ? Qt : Qnil;
917 }
918 }
919
920 return Qnil;
921 }
922
923 /* Called at device-creation time to initialize the user-defined
924 tag values for the newly-created device. */
925
926 void
927 setup_device_initial_specifier_tags (struct device *d)
928 {
929 Lisp_Object rest, rest2;
930 Lisp_Object device = Qnil;
931
932 XSETDEVICE (device, d);
933
934 DEVICE_USER_DEFINED_TAGS (d) = Fcopy_alist (Vuser_defined_tags);
935
936 /* Now set up the initial values */
937 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
938 XCDR (XCAR (rest)) = Qt;
939
940 for (rest = Vuser_defined_tags, rest2 = DEVICE_USER_DEFINED_TAGS (d);
941 !NILP (rest); rest = XCDR (rest), rest2 = XCDR (rest2))
942 {
943 Lisp_Object predicate = XCDR (XCAR (rest));
944 if (NILP (predicate))
945 XCDR (XCAR (rest2)) = Qt;
946 else
947 XCDR (XCAR (rest2)) = !NILP (call1 (predicate, device)) ? Qt : Qnil;
948 }
949 }
950
951 DEFUN ("device-matching-specifier-tag-list",
952 Fdevice_matching_specifier_tag_list,
953 Sdevice_matching_specifier_tag_list,
954 0, 1, 0 /*
955 Return a list of all specifier tags matching DEVICE.
956 DEVICE defaults to the selected device if omitted.
957 */ )
958 (device)
959 Lisp_Object device;
960 {
961 struct device *d = decode_device (device);
962 Lisp_Object rest, list = Qnil;
963 struct gcpro gcpro1;
964
965 GCPRO1 (list);
966
967 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
968 {
969 if (!NILP (XCDR (XCAR (rest))))
970 list = Fcons (XCAR (XCAR (rest)), list);
971 }
972
973 list = Fnreverse (list);
974 list = Fcons (DEVICE_CLASS (d), list);
975 list = Fcons (DEVICE_TYPE (d), list);
976
977 RETURN_UNGCPRO (list);
978 }
979
980 DEFUN ("specifier-tag-list", Fspecifier_tag_list, Sspecifier_tag_list,
981 0, 0, 0 /*
982 Return a list of all currently-defined specifier tags.
983 This includes the built-in ones (the device types and classes).
984 */ )
985 ()
986 {
987 Lisp_Object list = Qnil, rest;
988 struct gcpro gcpro1;
989
990 GCPRO1 (list);
991
992 LIST_LOOP (rest, Vuser_defined_tags)
993 list = Fcons (XCAR (XCAR (rest)), list);
994
995 list = Fnreverse (list);
996 list = nconc2 (Fcopy_sequence (Vdevice_class_list), list);
997 list = nconc2 (Fcopy_sequence (Vconsole_type_list), list);
998
999 RETURN_UNGCPRO (list);
1000 }
1001
1002 DEFUN ("specifier-tag-predicate", Fspecifier_tag_predicate,
1003 Sspecifier_tag_predicate,
1004 1, 1, 0 /*
1005 Return the predicate for the given specifier tag.
1006 */ )
1007 (tag)
1008 Lisp_Object tag;
1009 {
1010 /* The return value of this function must be GCPRO'd. */
1011 CHECK_SYMBOL (tag);
1012
1013 if (NILP (Fvalid_specifier_tag_p (tag)))
1014 signal_simple_error ("Invalid specifier tag", tag);
1015
1016 /* Make up some predicates for the built-in types */
1017
1018 if (valid_console_type_p (tag))
1019 return list3 (Qlambda, list1 (Qdevice),
1020 list3 (Qeq, list2 (Qquote, tag),
1021 list2 (Qconsole_type, Qdevice)));
1022
1023 if (valid_device_class_p (tag))
1024 return list3 (Qlambda, list1 (Qdevice),
1025 list3 (Qeq, list2 (Qquote, tag),
1026 list2 (Qdevice_class, Qdevice)));
1027
1028 return XCDR (assq_no_quit (tag, Vuser_defined_tags));
1029 }
1030
1031 /* Return true if A "matches" B. If EXACT_P is 0, A must be a subset of B.
1032 Otherwise, A must be `equal' to B. The sets must be canonicalized. */
1033 static int
1034 tag_sets_match_p (Lisp_Object a, Lisp_Object b, int exact_p)
1035 {
1036 if (!exact_p)
1037 {
1038 while (!NILP (a) && !NILP (b))
1039 {
1040 if (EQ (XCAR (a), XCAR (b)))
1041 a = XCDR (a);
1042 b = XCDR (b);
1043 }
1044
1045 return NILP (a);
1046 }
1047 else
1048 {
1049 while (!NILP (a) && !NILP (b))
1050 {
1051 if (!EQ (XCAR (a), XCAR (b)))
1052 return 0;
1053 a = XCDR (a);
1054 b = XCDR (b);
1055 }
1056
1057 return NILP (a) && NILP (b);
1058 }
1059 }
1060
1061
1062 /************************************************************************/
1063 /* Spec-lists and inst-lists */
1064 /************************************************************************/
1065
1066 static Lisp_Object
1067 call_validate_method (Lisp_Object boxed_method, Lisp_Object instantiator)
1068 {
1069 ((void (*)(Lisp_Object)) get_opaque_ptr (boxed_method)) (instantiator);
1070 return Qt;
1071 }
1072
1073 static Lisp_Object
1074 check_valid_instantiator (Lisp_Object instantiator,
1075 struct specifier_methods *meths,
1076 Error_behavior errb)
1077 {
1078 if (meths->validate_method)
1079 {
1080 Lisp_Object retval;
1081
1082 if (ERRB_EQ (errb, ERROR_ME))
1083 {
1084 (meths->validate_method) (instantiator);
1085 retval = Qt;
1086 }
1087 else
1088 {
1089 Lisp_Object opaque = make_opaque_ptr ((void *)
1090 meths->validate_method);
1091 struct gcpro gcpro1;
1092
1093 GCPRO1 (opaque);
1094 retval = call_with_suspended_errors (call_validate_method,
1095 Qnil,
1096 Qspecifier, errb, 2,
1097 opaque, instantiator);
1098 free_opaque_ptr (opaque);
1099 UNGCPRO;
1100 }
1101
1102 return retval;
1103 }
1104 return Qt;
1105 }
1106
1107 DEFUN ("check-valid-instantiator", Fcheck_valid_instantiator,
1108 Scheck_valid_instantiator,
1109 2, 2, 0 /*
1110 Signal an error if INSTANTIATOR is invalid for SPECIFIER-TYPE.
1111 */ )
1112 (instantiator, specifier_type)
1113 Lisp_Object instantiator, specifier_type;
1114 {
1115 struct specifier_methods *meths = decode_specifier_type (specifier_type,
1116 ERROR_ME);
1117
1118 return check_valid_instantiator (instantiator, meths, ERROR_ME);
1119 }
1120
1121 DEFUN ("valid-instantiator-p", Fvalid_instantiator_p, Svalid_instantiator_p,
1122 2, 2, 0 /*
1123 Return non-nil if INSTANTIATOR is valid for SPECIFIER-TYPE.
1124 */ )
1125 (instantiator, specifier_type)
1126 Lisp_Object instantiator, specifier_type;
1127 {
1128 struct specifier_methods *meths = decode_specifier_type (specifier_type,
1129 ERROR_ME);
1130
1131 return check_valid_instantiator (instantiator, meths, ERROR_ME_NOT);
1132 }
1133
1134 static Lisp_Object
1135 check_valid_inst_list (Lisp_Object inst_list, struct specifier_methods *meths,
1136 Error_behavior errb)
1137 {
1138 Lisp_Object rest;
1139
1140 LIST_LOOP (rest, inst_list)
1141 {
1142 if (!CONSP (rest) || !CONSP (XCAR (rest)))
1143 {
1144 maybe_signal_simple_error ("Invalid instantiator list", inst_list,
1145 Qspecifier, errb);
1146 return Qnil;
1147 }
1148 if (NILP (Fvalid_specifier_tag_set_p (XCAR (XCAR (rest)))))
1149 {
1150 maybe_signal_simple_error ("Invalid specifier tag",
1151 XCAR (XCAR (rest)), Qspecifier, errb);
1152 return Qnil;
1153 }
1154
1155 if (NILP (check_valid_instantiator (XCDR (XCAR (rest)), meths,
1156 errb)))
1157 return Qnil;
1158 }
1159
1160 return Qt;
1161 }
1162
1163 DEFUN ("check-valid-inst-list", Fcheck_valid_inst_list, Scheck_valid_inst_list,
1164 2, 2, 0 /*
1165 Signal an error if INST-LIST is invalid for specifier type TYPE.
1166 */ )
1167 (inst_list, type)
1168 Lisp_Object inst_list, type;
1169 {
1170 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1171
1172 return check_valid_inst_list (inst_list, meths, ERROR_ME);
1173 }
1174
1175 DEFUN ("valid-inst-list-p", Fvalid_inst_list_p, Svalid_inst_list_p,
1176 2, 2, 0 /*
1177 Return non-nil if INST-LIST is valid for specifier type TYPE.
1178 */ )
1179 (inst_list, type)
1180 Lisp_Object inst_list, type;
1181 {
1182 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1183
1184 return check_valid_inst_list (inst_list, meths, ERROR_ME_NOT);
1185 }
1186
1187 static Lisp_Object
1188 check_valid_spec_list (Lisp_Object spec_list, struct specifier_methods *meths,
1189 Error_behavior errb)
1190 {
1191 Lisp_Object rest;
1192
1193 LIST_LOOP (rest, spec_list)
1194 {
1195 if (!CONSP (rest) || !CONSP (XCAR (rest)))
1196 {
1197 maybe_signal_simple_error ("Invalid specification list", spec_list,
1198 Qspecifier, errb);
1199 return Qnil;
1200 }
1201 if (NILP (Fvalid_specifier_locale_p (XCAR (XCAR (rest)))))
1202 {
1203 maybe_signal_simple_error ("Invalid specifier locale",
1204 XCAR (XCAR (rest)),
1205 Qspecifier, errb);
1206 return Qnil;
1207 }
1208
1209 if (NILP (check_valid_inst_list (XCDR (XCAR (rest)), meths, errb)))
1210 return Qnil;
1211 }
1212
1213 return Qt;
1214 }
1215
1216 DEFUN ("check-valid-spec-list", Fcheck_valid_spec_list, Scheck_valid_spec_list,
1217 2, 2, 0 /*
1218 Signal an error if SPEC-LIST is invalid for specifier type TYPE.
1219 */ )
1220 (spec_list, type)
1221 Lisp_Object spec_list, type;
1222 {
1223 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1224
1225 return check_valid_spec_list (spec_list, meths, ERROR_ME);
1226 }
1227
1228 DEFUN ("valid-spec-list-p", Fvalid_spec_list_p, Svalid_spec_list_p,
1229 2, 2, 0 /*
1230 Return non-nil if SPEC-LIST is valid for specifier type TYPE.
1231 */ )
1232 (spec_list, type)
1233 Lisp_Object spec_list, type;
1234 {
1235 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1236
1237 return check_valid_spec_list (spec_list, meths, ERROR_ME_NOT);
1238 }
1239
1240 enum spec_add_meth
1241 decode_how_to_add_specification (Lisp_Object how_to_add)
1242 {
1243 enum spec_add_meth add_meth = 0;
1244
1245 if (NILP (how_to_add) || EQ (Qremove_tag_set_prepend, how_to_add))
1246 add_meth = SPEC_REMOVE_TAG_SET_PREPEND;
1247 else if (EQ (Qremove_tag_set_append, how_to_add))
1248 add_meth = SPEC_REMOVE_TAG_SET_APPEND;
1249 else if (EQ (Qappend, how_to_add))
1250 add_meth = SPEC_APPEND;
1251 else if (EQ (Qprepend, how_to_add))
1252 add_meth = SPEC_PREPEND;
1253 else if (EQ (Qremove_locale, how_to_add))
1254 add_meth = SPEC_REMOVE_LOCALE;
1255 else if (EQ (Qremove_locale_type, how_to_add))
1256 add_meth = SPEC_REMOVE_LOCALE_TYPE;
1257 else if (EQ (Qremove_all, how_to_add))
1258 add_meth = SPEC_REMOVE_ALL;
1259 else
1260 signal_simple_error ("Invalid `how-to-add' flag", how_to_add);
1261 return add_meth;
1262 }
1263
1264 /* This gets hit so much that the function call overhead had a
1265 measurable impact (according to Quantify). #### We should figure
1266 out the frequency with which this is called with the various types
1267 and reorder the check accordingly. */
1268 #define SPECIFIER_GET_SPEC_LIST(specifier, type) \
1269 (type == LOCALE_GLOBAL \
1270 ? &(XSPECIFIER (specifier)->global_specs) \
1271 : (type == LOCALE_DEVICE \
1272 ? &(XSPECIFIER (specifier)->device_specs) \
1273 : (type == LOCALE_FRAME \
1274 ? &(XSPECIFIER (specifier)->frame_specs) \
1275 : (type == LOCALE_WINDOW \
1276 ? &(XWEAK_LIST_LIST (XSPECIFIER (specifier)->window_specs)) \
1277 : (type == LOCALE_BUFFER \
1278 ? &(XSPECIFIER (specifier)->buffer_specs) \
1279 : 0)))))
1280
1281 static Lisp_Object *
1282 specifier_get_inst_list (Lisp_Object specifier, Lisp_Object locale,
1283 enum spec_locale_type type)
1284 {
1285 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1286 Lisp_Object specification;
1287
1288 if (type == LOCALE_GLOBAL)
1289 return spec_list;
1290 /* Calling assq_no_quit when it is just going to return nil anyhow
1291 is extremely expensive. So sayeth Quantify. */
1292 if (!CONSP (*spec_list))
1293 return 0;
1294 specification = assq_no_quit (locale, *spec_list);
1295 if (NILP (specification))
1296 return 0;
1297 return &XCDR (specification);
1298 }
1299
1300 /* For the given INST_LIST, return a new INST_LIST containing all elements
1301 where TAG-SET matches the element's tag set. EXACT_P indicates whether
1302 the match must be exact (as opposed to a subset). SHORT_P indicates
1303 that the short form (for `specifier-specs') should be returned if
1304 possible. If COPY_TREE_P, `copy-tree' is used to ensure that no
1305 elements of the new list are shared with the initial list.
1306 */
1307
1308 static Lisp_Object
1309 specifier_process_inst_list (Lisp_Object inst_list,
1310 Lisp_Object tag_set, int exact_p,
1311 int short_p, int copy_tree_p)
1312 {
1313 Lisp_Object retval = Qnil;
1314 Lisp_Object rest;
1315 struct gcpro gcpro1;
1316
1317 GCPRO1 (retval);
1318 LIST_LOOP (rest, inst_list)
1319 {
1320 Lisp_Object tagged_inst = XCAR (rest);
1321 Lisp_Object tagged_inst_tag = XCAR (tagged_inst);
1322 if (tag_sets_match_p (tag_set, tagged_inst_tag, exact_p))
1323 {
1324 if (short_p && NILP (tagged_inst_tag))
1325 retval = Fcons (copy_tree_p ?
1326 Fcopy_tree (XCDR (tagged_inst), Qt) :
1327 XCDR (tagged_inst),
1328 retval);
1329 else
1330 retval = Fcons (copy_tree_p ? Fcopy_tree (tagged_inst, Qt) :
1331 tagged_inst, retval);
1332 }
1333 }
1334 retval = Fnreverse (retval);
1335 UNGCPRO;
1336 /* If there is a single instantiator and the short form is
1337 requested, return just the instantiator (rather than a one-element
1338 list of it) unless it is nil (so that it can be distinguished from
1339 no instantiators at all). */
1340 if (short_p && CONSP (retval) && !NILP (XCAR (retval)) &&
1341 NILP (XCDR (retval)))
1342 return XCAR (retval);
1343 else
1344 return retval;
1345 }
1346
1347 static Lisp_Object
1348 specifier_get_external_inst_list (Lisp_Object specifier, Lisp_Object locale,
1349 enum spec_locale_type type,
1350 Lisp_Object tag_set, int exact_p,
1351 int short_p, int copy_tree_p)
1352 {
1353 Lisp_Object *inst_list = specifier_get_inst_list (specifier, locale,
1354 type);
1355 if (!inst_list || NILP (*inst_list))
1356 {
1357 /* nil for *inst_list should only occur in 'global */
1358 assert (!inst_list || EQ (locale, Qglobal));
1359 return Qnil;
1360 }
1361
1362 return specifier_process_inst_list (*inst_list, tag_set, exact_p,
1363 short_p, copy_tree_p);
1364 }
1365
1366 static Lisp_Object
1367 specifier_get_external_spec_list (Lisp_Object specifier,
1368 enum spec_locale_type type,
1369 Lisp_Object tag_set, int exact_p)
1370 {
1371 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1372 Lisp_Object retval = Qnil;
1373 Lisp_Object rest;
1374 struct gcpro gcpro1;
1375
1376 assert (type != LOCALE_GLOBAL);
1377 /* We're about to let stuff go external; make sure there aren't
1378 any dead objects */
1379 *spec_list = cleanup_assoc_list (*spec_list);
1380
1381 GCPRO1 (retval);
1382 LIST_LOOP (rest, *spec_list)
1383 {
1384 Lisp_Object spec = XCAR (rest);
1385 Lisp_Object inst_list =
1386 specifier_process_inst_list (XCDR (spec), tag_set, exact_p, 0, 1);
1387 if (!NILP (inst_list))
1388 retval = Fcons (Fcons (XCAR (spec), inst_list), retval);
1389 }
1390 RETURN_UNGCPRO (Fnreverse (retval));
1391 }
1392
1393 static Lisp_Object *
1394 specifier_new_spec (Lisp_Object specifier, Lisp_Object locale,
1395 enum spec_locale_type type)
1396 {
1397 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1398 Lisp_Object new_spec = Fcons (locale, Qnil);
1399 assert (type != LOCALE_GLOBAL);
1400 *spec_list = Fcons (new_spec, *spec_list);
1401 return &XCDR (new_spec);
1402 }
1403
1404 /* For the given INST_LIST, return a new list comprised of elements
1405 where TAG_SET does not match the element's tag set. This operation
1406 is destructive. */
1407
1408 static Lisp_Object
1409 specifier_process_remove_inst_list (Lisp_Object inst_list,
1410 Lisp_Object tag_set, int exact_p,
1411 int *was_removed)
1412 {
1413 Lisp_Object prev = Qnil, rest;
1414
1415 *was_removed = 0;
1416
1417 LIST_LOOP (rest, inst_list)
1418 {
1419 if (tag_sets_match_p (tag_set, XCAR (XCAR (rest)), exact_p))
1420 {
1421 /* time to remove. */
1422 *was_removed = 1;
1423 if (NILP (prev))
1424 inst_list = XCDR (rest);
1425 else
1426 XCDR (prev) = XCDR (rest);
1427 }
1428 else
1429 prev = rest;
1430 }
1431
1432 return inst_list;
1433 }
1434
1435 static void
1436 specifier_remove_spec (Lisp_Object specifier, Lisp_Object locale,
1437 enum spec_locale_type type,
1438 Lisp_Object tag_set, int exact_p)
1439 {
1440 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1441 Lisp_Object assoc;
1442 int was_removed;
1443
1444 if (type == LOCALE_GLOBAL)
1445 *spec_list = specifier_process_remove_inst_list (*spec_list, tag_set,
1446 exact_p, &was_removed);
1447 else
1448 {
1449 assoc = assq_no_quit (locale, *spec_list);
1450 if (NILP (assoc))
1451 /* this locale is not found. */
1452 return;
1453 XCDR (assoc) = specifier_process_remove_inst_list (XCDR (assoc),
1454 tag_set, exact_p,
1455 &was_removed);
1456 if (NILP (XCDR (assoc)))
1457 /* no inst-pairs left; remove this locale entirely. */
1458 *spec_list = remassq_no_quit (locale, *spec_list);
1459 }
1460
1461 if (was_removed)
1462 MAYBE_SPECMETH (XSPECIFIER (specifier), after_change, (specifier, locale));
1463 }
1464
1465 static void
1466 specifier_remove_locale_type (Lisp_Object specifier,
1467 enum spec_locale_type type,
1468 Lisp_Object tag_set, int exact_p)
1469 {
1470 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1471 Lisp_Object prev = Qnil, rest;
1472
1473 assert (type != LOCALE_GLOBAL);
1474 LIST_LOOP (rest, *spec_list)
1475 {
1476 int was_removed;
1477 int remove_spec = 0;
1478 Lisp_Object spec = XCAR (rest);
1479
1480 /* There may be dead objects floating around */
1481 /* remember, dead windows can become alive again. */
1482 if (!WINDOWP (XCAR (spec)) && object_dead_p (XCAR (spec)))
1483 {
1484 remove_spec = 1;
1485 was_removed = 0;
1486 }
1487 else
1488 {
1489 XCDR (spec) = specifier_process_remove_inst_list (XCDR (spec),
1490 tag_set, exact_p,
1491 &was_removed);
1492 if (NILP (XCDR (spec)))
1493 remove_spec = 1;
1494 }
1495
1496 if (remove_spec)
1497 {
1498 if (NILP (prev))
1499 *spec_list = XCDR (rest);
1500 else
1501 XCDR (prev) = XCDR (rest);
1502 }
1503 else
1504 prev = rest;
1505
1506 if (was_removed)
1507 MAYBE_SPECMETH (XSPECIFIER (specifier), after_change,
1508 (specifier, XCAR (spec)));
1509 }
1510 }
1511
1512 /* NEW_LIST is going to be added to INST_LIST, with add method ADD_METH.
1513 Frob INST_LIST according to ADD_METH. No need to call an after-change
1514 function; the calling function will do this. Return either SPEC_PREPEND
1515 or SPEC_APPEND, indicating whether to prepend or append the NEW_LIST. */
1516
1517 static enum spec_add_meth
1518 handle_multiple_add_insts (Lisp_Object *inst_list,
1519 Lisp_Object new_list,
1520 enum spec_add_meth add_meth)
1521 {
1522 if (add_meth == SPEC_REMOVE_TAG_SET_PREPEND ||
1523 add_meth == SPEC_REMOVE_TAG_SET_APPEND)
1524 {
1525 Lisp_Object rest;
1526
1527 LIST_LOOP (rest, new_list)
1528 {
1529 Lisp_Object canontag = canonicalize_tag_set (XCAR (XCAR (rest)));
1530 struct gcpro gcpro1;
1531
1532 GCPRO1 (canontag);
1533 /* pull out all elements from the existing list with the
1534 same tag as any tags in NEW_LIST. */
1535 *inst_list = remassoc_no_quit (canontag, *inst_list);
1536 UNGCPRO;
1537 }
1538 if (add_meth == SPEC_REMOVE_TAG_SET_PREPEND)
1539 return SPEC_PREPEND;
1540 else
1541 return SPEC_APPEND;
1542 }
1543 else if (add_meth == SPEC_REMOVE_LOCALE)
1544 {
1545 *inst_list = Qnil;
1546 return SPEC_PREPEND;
1547 }
1548 if (add_meth == SPEC_APPEND)
1549 return add_meth;
1550
1551 return SPEC_PREPEND;
1552 }
1553
1554 /* Given a LOCALE and INST_LIST that is going to be added to SPECIFIER,
1555 copy, canonicalize, and call the going_to_add methods as necessary
1556 to produce a new list that is the one that really will be added
1557 to the specifier. */
1558
1559 static Lisp_Object
1560 build_up_processed_list (Lisp_Object specifier, Lisp_Object locale,
1561 Lisp_Object inst_list)
1562 {
1563 /* The return value of this function must be GCPRO'd. */
1564 Lisp_Object rest, list_to_build_up = Qnil;
1565 struct gcpro gcpro1;
1566
1567 GCPRO1 (list_to_build_up);
1568 LIST_LOOP (rest, inst_list)
1569 {
1570 Lisp_Object tag_set = XCAR (XCAR (rest));
1571 Lisp_Object instantiator = Fcopy_tree (XCDR (XCAR (rest)), Qt);
1572 Lisp_Object sub_inst_list = Qnil;
1573 struct gcpro ngcpro1, ngcpro2;
1574
1575 NGCPRO2 (instantiator, sub_inst_list);
1576 /* call the will-add method; it may GC */
1577 sub_inst_list = SPECMETH_OR_GIVEN (XSPECIFIER (specifier), going_to_add,
1578 (specifier, locale, tag_set,
1579 instantiator), Qt);
1580 if (EQ (sub_inst_list, Qt))
1581 /* no change here. */
1582 sub_inst_list = list1 (Fcons (canonicalize_tag_set (tag_set),
1583 instantiator));
1584 else
1585 {
1586 /* now canonicalize all the tag sets in the new objects */
1587 Lisp_Object rest2;
1588 LIST_LOOP (rest2, sub_inst_list)
1589 XCAR (XCAR (rest2)) = canonicalize_tag_set (XCAR (XCAR (rest2)));
1590 }
1591
1592 list_to_build_up = nconc2 (sub_inst_list, list_to_build_up);
1593 NUNGCPRO;
1594 }
1595
1596 RETURN_UNGCPRO (Fnreverse (list_to_build_up));
1597 }
1598
1599 /* Add a specification (locale and instantiator list) to a specifier.
1600 ADD_METH specifies what to do with existing specifications in the
1601 specifier, and is an enum that corresponds to the values in
1602 `add-spec-to-specifier'. The calling routine is responsible for
1603 validating LOCALE and INST-LIST, but the tag-sets in INST-LIST
1604 do not need to be canonicalized. */
1605
1606 /* #### I really need to rethink the after-change
1607 functions to make them easier to use and more efficient. */
1608
1609 static void
1610 specifier_add_spec (Lisp_Object specifier, Lisp_Object locale,
1611 Lisp_Object inst_list, enum spec_add_meth add_meth)
1612 {
1613 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
1614 enum spec_locale_type type;
1615 Lisp_Object *orig_inst_list;
1616 Lisp_Object list_to_build_up = Qnil;
1617 struct gcpro gcpro1;
1618
1619 type = locale_type_from_locale (locale);
1620
1621 GCPRO1 (list_to_build_up);
1622 list_to_build_up = build_up_processed_list (specifier, locale, inst_list);
1623 /* Now handle REMOVE_LOCALE_TYPE and REMOVE_ALL. These are the
1624 add-meth types that affect locales other than this one. */
1625 if (add_meth == SPEC_REMOVE_LOCALE_TYPE)
1626 specifier_remove_locale_type (specifier, type, Qnil, 0);
1627 else if (add_meth == SPEC_REMOVE_ALL)
1628 {
1629 specifier_remove_locale_type (specifier, LOCALE_BUFFER, Qnil, 0);
1630 specifier_remove_locale_type (specifier, LOCALE_WINDOW, Qnil, 0);
1631 specifier_remove_locale_type (specifier, LOCALE_FRAME, Qnil, 0);
1632 specifier_remove_locale_type (specifier, LOCALE_DEVICE, Qnil, 0);
1633 specifier_remove_spec (specifier, Qglobal, LOCALE_GLOBAL, Qnil, 0);
1634 }
1635
1636 orig_inst_list = specifier_get_inst_list (specifier, locale, type);
1637 if (!orig_inst_list)
1638 orig_inst_list = specifier_new_spec (specifier, locale, type);
1639 add_meth = handle_multiple_add_insts (orig_inst_list, list_to_build_up,
1640 add_meth);
1641
1642 if (add_meth == SPEC_PREPEND)
1643 {
1644 *orig_inst_list = nconc2 (list_to_build_up, *orig_inst_list);
1645 }
1646 else if (add_meth == SPEC_APPEND)
1647 {
1648 *orig_inst_list = nconc2 (*orig_inst_list, list_to_build_up);
1649 }
1650 else
1651 abort ();
1652
1653 UNGCPRO;
1654
1655 /* call the after-change method */
1656 MAYBE_SPECMETH (sp, after_change, (specifier, locale));
1657 }
1658
1659 static void
1660 specifier_copy_spec (Lisp_Object specifier, Lisp_Object dest,
1661 Lisp_Object locale, enum spec_locale_type type,
1662 Lisp_Object tag_set, int exact_p,
1663 enum spec_add_meth add_meth)
1664 {
1665 Lisp_Object inst_list =
1666 specifier_get_external_inst_list (specifier, locale, type, tag_set,
1667 exact_p, 0, 0);
1668 specifier_add_spec (dest, locale, inst_list, add_meth);
1669 }
1670
1671 static void
1672 specifier_copy_locale_type (Lisp_Object specifier, Lisp_Object dest,
1673 enum spec_locale_type type,
1674 Lisp_Object tag_set, int exact_p,
1675 enum spec_add_meth add_meth)
1676 {
1677 Lisp_Object *src_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1678 Lisp_Object rest;
1679
1680 /* This algorithm is O(n^2) in running time.
1681 It's certainly possible to implement an O(n log n) algorithm,
1682 but I doubt there's any need to. */
1683
1684 LIST_LOOP (rest, *src_list)
1685 {
1686 Lisp_Object spec = XCAR (rest);
1687 /* There may be dead objects floating around */
1688 /* remember, dead windows can become alive again. */
1689 if (WINDOWP (XCAR (spec)) || !object_dead_p (XCAR (spec)))
1690 specifier_add_spec
1691 (dest, XCAR (spec),
1692 specifier_process_inst_list (XCDR (spec), tag_set, exact_p, 0, 0),
1693 add_meth);
1694 }
1695 }
1696
1697 /* map MAPFUN over the locales in SPECIFIER that are given in LOCALE.
1698 CLOSURE is passed unchanged to MAPFUN. LOCALE can be one of
1699
1700 -- nil (same as 'all)
1701 -- a single locale, locale type, or 'all
1702 -- a list of locales, locale types, and/or 'all
1703
1704 MAPFUN is called for each locale and locale type given; for 'all,
1705 it is called for the locale 'global and for the four possible
1706 locale types. In each invocation, either LOCALE will be a locale
1707 and LOCALE_TYPE will be the locale type of this locale,
1708 or LOCALE will be nil and LOCALE_TYPE will be a locale type.
1709 If MAPFUN ever returns non-zero, the mapping is halted and the
1710 value returned is returned from map_specifier(). Otherwise, the
1711 mapping proceeds to the end and map_specifier() returns 0.
1712 */
1713
1714 static int
1715 map_specifier (Lisp_Object specifier, Lisp_Object locale,
1716 int (*mapfun) (Lisp_Object specifier,
1717 Lisp_Object locale,
1718 enum spec_locale_type locale_type,
1719 Lisp_Object tag_set,
1720 int exact_p,
1721 void *closure),
1722 Lisp_Object tag_set, Lisp_Object exact_p,
1723 void *closure)
1724 {
1725 int retval = 0;
1726 Lisp_Object rest;
1727 struct gcpro gcpro1, gcpro2;
1728
1729 GCPRO2 (tag_set, locale);
1730 locale = decode_locale_list (locale);
1731 tag_set = decode_specifier_tag_set (tag_set);
1732 tag_set = canonicalize_tag_set (tag_set);
1733
1734 LIST_LOOP (rest, locale)
1735 {
1736 Lisp_Object theloc = XCAR (rest);
1737 if (!NILP (Fvalid_specifier_locale_p (theloc)))
1738 {
1739 retval = (*mapfun) (specifier, theloc,
1740 locale_type_from_locale (theloc),
1741 tag_set, !NILP (exact_p), closure);
1742 if (retval)
1743 break;
1744 }
1745 else if (!NILP (Fvalid_specifier_locale_type_p (theloc)))
1746 {
1747 retval = (*mapfun) (specifier, Qnil,
1748 decode_locale_type (theloc), tag_set,
1749 !NILP (exact_p), closure);
1750 if (retval)
1751 break;
1752 }
1753 else
1754 {
1755 assert (EQ (theloc, Qall));
1756 retval = (*mapfun) (specifier, Qnil, LOCALE_BUFFER, tag_set,
1757 !NILP (exact_p), closure);
1758 if (retval)
1759 break;
1760 retval = (*mapfun) (specifier, Qnil, LOCALE_WINDOW, tag_set,
1761 !NILP (exact_p), closure);
1762 if (retval)
1763 break;
1764 retval = (*mapfun) (specifier, Qnil, LOCALE_FRAME, tag_set,
1765 !NILP (exact_p), closure);
1766 if (retval)
1767 break;
1768 retval = (*mapfun) (specifier, Qnil, LOCALE_DEVICE, tag_set,
1769 !NILP (exact_p), closure);
1770 if (retval)
1771 break;
1772 retval = (*mapfun) (specifier, Qglobal, LOCALE_GLOBAL, tag_set,
1773 !NILP (exact_p), closure);
1774 if (retval)
1775 break;
1776 }
1777 }
1778
1779 UNGCPRO;
1780 return retval;
1781 }
1782
1783 DEFUN ("add-spec-to-specifier", Fadd_spec_to_specifier, Sadd_spec_to_specifier,
1784 2, 5, 0 /*
1785 Add a specification to SPECIFIER.
1786 The specification maps from LOCALE (which should be a buffer, window,
1787 frame, device, or 'global, and defaults to 'global) to INSTANTIATOR,
1788 whose allowed values depend on the type of the specifier. Optional
1789 argument TAG-SET limits the instantiator to apply only to the specified
1790 tag set, which should be a list of tags all of which must match the
1791 device being instantiated over (tags are a device type, a device class,
1792 or tags defined with `define-specifier-tag'). Specifying a single
1793 symbol for TAG-SET is equivalent to specifying a one-element list
1794 containing that symbol. Optional argument HOW-TO-ADD specifies what to
1795 do if there are already specifications in the specifier.
1796 It should be one of
1797
1798 'prepend Put at the beginning of the current list of
1799 instantiators for LOCALE.
1800 'append Add to the end of the current list of
1801 instantiators for LOCALE.
1802 'remove-tag-set-prepend (this is the default)
1803 Remove any existing instantiators whose tag set is
1804 the same as TAG-SET; then put the new instantiator
1805 at the beginning of the current list. (\"Same tag
1806 set\" means that they contain the same elements.
1807 The order may be different.)
1808 'remove-tag-set-append
1809 Remove any existing instantiators whose tag set is
1810 the same as TAG-SET; then put the new instantiator
1811 at the end of the current list.
1812 'remove-locale Remove all previous instantiators for this locale
1813 before adding the new spec.
1814 'remove-locale-type Remove all specifications for all locales of the
1815 same type as LOCALE (this includes LOCALE itself)
1816 before adding the new spec.
1817 'remove-all Remove all specifications from the specifier
1818 before adding the new spec.
1819
1820 You can retrieve the specifications for a particular locale or locale type
1821 with the function `specifier-spec-list' or `specifier-specs'.
1822 */ )
1823 (specifier, instantiator, locale, tag_set, how_to_add)
1824 Lisp_Object specifier, instantiator, locale, tag_set, how_to_add;
1825 {
1826 enum spec_add_meth add_meth;
1827 Lisp_Object inst_list;
1828 struct gcpro gcpro1;
1829
1830 CHECK_SPECIFIER (specifier);
1831 locale = decode_locale (locale);
1832 check_valid_instantiator (instantiator,
1833 decode_specifier_type
1834 (Fspecifier_type (specifier), ERROR_ME),
1835 ERROR_ME);
1836 /* tag_set might be newly-created material, but it's part of inst_list
1837 so is properly GC-protected. */
1838 tag_set = decode_specifier_tag_set (tag_set);
1839 add_meth = decode_how_to_add_specification (how_to_add);
1840
1841 inst_list = list1 (Fcons (tag_set, instantiator));
1842 GCPRO1 (inst_list);
1843 specifier_add_spec (specifier, locale, inst_list, add_meth);
1844 recompute_cached_specifier_everywhere (specifier);
1845 RETURN_UNGCPRO (Qnil);
1846 }
1847
1848 DEFUN ("add-spec-list-to-specifier", Fadd_spec_list_to_specifier,
1849 Sadd_spec_list_to_specifier, 2, 3, 0 /*
1850 Add a spec-list (a list of specifications) to SPECIFIER.
1851 The format of a spec-list is
1852
1853 ((LOCALE (TAG-SET . INSTANTIATOR) ...) ...)
1854
1855 where
1856 LOCALE := a buffer, a window, a frame, a device, or 'global
1857 TAG-SET := an unordered list of zero or more TAGS, each of which
1858 is a symbol
1859 TAG := a device class (see `valid-device-class-p'), a device type
1860 (see `valid-console-type-p'), or a tag defined with
1861 `define-specifier-tag'
1862 INSTANTIATOR := format determined by the type of specifier
1863
1864 The pair (TAG-SET . INSTANTIATOR) is called an `inst-pair'.
1865 A list of inst-pairs is called an `inst-list'.
1866 The pair (LOCALE . INST-LIST) is called a `specification' or `spec'.
1867 A spec-list, then, can be viewed as a list of specifications.
1868
1869 HOW-TO-ADD specifies how to combine the new specifications with
1870 the existing ones, and has the same semantics as for
1871 `add-spec-to-specifier'.
1872
1873 In many circumstances, the higher-level function `set-specifier' is
1874 more convenient and should be used instead.
1875 */ )
1876 (specifier, spec_list, how_to_add)
1877 Lisp_Object specifier, spec_list, how_to_add;
1878 {
1879 enum spec_add_meth add_meth;
1880 Lisp_Object rest;
1881
1882 CHECK_SPECIFIER (specifier);
1883 check_valid_spec_list (spec_list,
1884 decode_specifier_type
1885 (Fspecifier_type (specifier), ERROR_ME),
1886 ERROR_ME);
1887 add_meth = decode_how_to_add_specification (how_to_add);
1888
1889 LIST_LOOP (rest, spec_list)
1890 {
1891 /* Placating the GCC god. */
1892 Lisp_Object crock1 = specifier;
1893 Lisp_Object crock2 = XCAR (XCAR (rest));
1894 Lisp_Object crock3 = XCDR (XCAR (rest));
1895
1896 specifier_add_spec (crock1, crock2, crock3, add_meth);
1897 }
1898 recompute_cached_specifier_everywhere (specifier);
1899 return Qnil;
1900 }
1901
1902 struct specifier_spec_list_closure
1903 {
1904 Lisp_Object head, tail;
1905 };
1906
1907 static int
1908 specifier_spec_list_mapfun (Lisp_Object specifier,
1909 Lisp_Object locale,
1910 enum spec_locale_type locale_type,
1911 Lisp_Object tag_set,
1912 int exact_p,
1913 void *closure)
1914 {
1915 struct specifier_spec_list_closure *cl =
1916 (struct specifier_spec_list_closure *) closure;
1917 Lisp_Object partial;
1918
1919 if (NILP (locale))
1920 partial = specifier_get_external_spec_list (specifier,
1921 locale_type,
1922 tag_set, exact_p);
1923 else
1924 {
1925 partial = specifier_get_external_inst_list (specifier, locale,
1926 locale_type, tag_set,
1927 exact_p, 0, 1);
1928 if (!NILP (partial))
1929 partial = list1 (Fcons (locale, partial));
1930 }
1931 if (NILP (partial))
1932 return 0;
1933
1934 /* tack on the new list */
1935 if (NILP (cl->tail))
1936 cl->head = cl->tail = partial;
1937 else
1938 XCDR (cl->tail) = partial;
1939 /* find the new tail */
1940 while (CONSP (XCDR (cl->tail)))
1941 cl->tail = XCDR (cl->tail);
1942 return 0;
1943 }
1944
1945 /* For the given SPECIFIER create and return a list of all specs
1946 contained within it, subject to LOCALE. If LOCALE is a locale, only
1947 specs in that locale will be returned. If LOCALE is a locale type,
1948 all specs in all locales of that type will be returned. If LOCALE is
1949 nil, all specs will be returned. This always copies lists and never
1950 returns the actual lists, because we do not want someone manipulating
1951 the actual objects. This may cause a slight loss of potential
1952 functionality but if we were to allow it then a user could manage to
1953 violate our assertion that the specs contained in the actual
1954 specifier lists are all valid. */
1955
1956 DEFUN ("specifier-spec-list", Fspecifier_spec_list, Sspecifier_spec_list,
1957 1, 4, 0 /*
1958 Return the spec-list of specifications for SPECIFIER in LOCALE.
1959
1960 If LOCALE is a particular locale (a buffer, window, frame, device,
1961 or 'global), a spec-list consisting of the specification for that
1962 locale will be returned.
1963
1964 If LOCALE is a locale type (i.e. 'buffer, 'window, 'frame, or 'device),
1965 a spec-list of the specifications for all locales of that type will be
1966 returned.
1967
1968 If LOCALE is nil or 'all, a spec-list of all specifications in SPECIFIER
1969 will be returned.
1970
1971 LOCALE can also be a list of locales, locale types, and/or 'all; the
1972 result is as if `specifier-spec-list' were called on each element of the
1973 list and the results concatenated together.
1974
1975 Only instantiators where TAG-SET (a list of zero or more tags) is a
1976 subset of (or possibly equal to) the instantiator's tag set are returned.
1977 (The default value of nil is a subset of all tag sets, so in this case
1978 no instantiators will be screened out.) If EXACT-P is non-nil, however,
1979 TAG-SET must be equal to an instantiator's tag set for the instantiator
1980 to be returned.
1981 */ )
1982 (specifier, locale, tag_set, exact_p)
1983 Lisp_Object specifier, locale, tag_set, exact_p;
1984 {
1985 struct specifier_spec_list_closure cl;
1986 struct gcpro gcpro1, gcpro2;
1987
1988 CHECK_SPECIFIER (specifier);
1989 cl.head = cl.tail = Qnil;
1990 GCPRO2 (cl.head, cl.tail);
1991 map_specifier (specifier, locale, specifier_spec_list_mapfun,
1992 tag_set, exact_p, &cl);
1993 UNGCPRO;
1994 return cl.head;
1995 }
1996
1997
1998 DEFUN ("specifier-specs", Fspecifier_specs, Sspecifier_specs,
1999 1, 4, 0 /*
2000 Return the specification(s) for SPECIFIER in LOCALE.
2001
2002 If LOCALE is a single locale or is a list of one element containing a
2003 single locale, then a \"short form\" of the instantiators for that locale
2004 will be returned. Otherwise, this function is identical to
2005 `specifier-spec-list'.
2006
2007 The \"short form\" is designed for readability and not for ease of use
2008 in Lisp programs, and is as follows:
2009
2010 1. If there is only one instantiator, then an inst-pair (i.e. cons of
2011 tag and instantiator) will be returned; otherwise a list of
2012 inst-pairs will be returned.
2013 2. For each inst-pair returned, if the instantiator's tag is 'any,
2014 the tag will be removed and the instantiator itself will be returned
2015 instead of the inst-pair.
2016 3. If there is only one instantiator, its value is nil, and its tag is
2017 'any, a one-element list containing nil will be returned rather
2018 than just nil, to distinguish this case from there being no
2019 instantiators at all.
2020 */ )
2021 (specifier, locale, tag_set, exact_p)
2022 Lisp_Object specifier, locale, tag_set, exact_p;
2023 {
2024 if (!NILP (Fvalid_specifier_locale_p (locale)) ||
2025 (CONSP (locale) && !NILP (Fvalid_specifier_locale_p (XCAR (locale))) &&
2026 NILP (XCDR (locale))))
2027 {
2028 struct gcpro gcpro1;
2029
2030 CHECK_SPECIFIER (specifier);
2031 if (CONSP (locale))
2032 locale = XCAR (locale);
2033 GCPRO1 (tag_set);
2034 tag_set = decode_specifier_tag_set (tag_set);
2035 tag_set = canonicalize_tag_set (tag_set);
2036 RETURN_UNGCPRO
2037 (specifier_get_external_inst_list (specifier, locale,
2038 locale_type_from_locale (locale),
2039 tag_set, !NILP (exact_p),
2040 1, 1));
2041 }
2042 else
2043 return Fspecifier_spec_list (specifier, locale, tag_set, exact_p);
2044 }
2045
2046 static int
2047 remove_specifier_mapfun (Lisp_Object specifier,
2048 Lisp_Object locale,
2049 enum spec_locale_type locale_type,
2050 Lisp_Object tag_set,
2051 int exact_p,
2052 void *ignored_closure)
2053 {
2054 if (NILP (locale))
2055 specifier_remove_locale_type (specifier, locale_type, tag_set, exact_p);
2056 else
2057 specifier_remove_spec (specifier, locale, locale_type, tag_set, exact_p);
2058 return 0;
2059 }
2060
2061 DEFUN ("remove-specifier", Fremove_specifier,
2062 Sremove_specifier, 1, 4, 0 /*
2063 Remove specification(s) for SPECIFIER.
2064
2065 If LOCALE is a particular locale (a buffer, window, frame, device,
2066 or 'global), the specification for that locale will be removed.
2067
2068 If instead, LOCALE is a locale type (i.e. 'buffer, 'window, 'frame,
2069 or 'device), the specifications for all locales of that type will be
2070 removed.
2071
2072 If LOCALE is nil or 'all, all specifications will be removed.
2073
2074 LOCALE can also be a list of locales, locale types, and/or 'all; this
2075 is equivalent to calling `remove-specifier' for each of the elements
2076 in the list.
2077
2078 Only instantiators where TAG-SET (a list of zero or more tags) is a
2079 subset of (or possibly equal to) the instantiator's tag set are removed.
2080 (The default value of nil is a subset of all tag sets, so in this case
2081 no instantiators will be screened out.) If EXACT-P is non-nil, however,
2082 TAG-SET must be equal to an instantiator's tag set for the instantiator
2083 to be removed.
2084 */ )
2085 (specifier, locale, tag_set, exact_p)
2086 Lisp_Object specifier, locale, tag_set, exact_p;
2087 {
2088 CHECK_SPECIFIER (specifier);
2089 map_specifier (specifier, locale, remove_specifier_mapfun, tag_set,
2090 exact_p, 0);
2091 recompute_cached_specifier_everywhere (specifier);
2092 return Qnil;
2093 }
2094
2095 struct copy_specifier_closure
2096 {
2097 Lisp_Object dest;
2098 enum spec_add_meth add_meth;
2099 int add_meth_is_nil;
2100 };
2101
2102 static int
2103 copy_specifier_mapfun (Lisp_Object specifier,
2104 Lisp_Object locale,
2105 enum spec_locale_type locale_type,
2106 Lisp_Object tag_set,
2107 int exact_p,
2108 void *closure)
2109 {
2110 struct copy_specifier_closure *cl =
2111 (struct copy_specifier_closure *) closure;
2112
2113 if (NILP (locale))
2114 specifier_copy_locale_type (specifier, cl->dest, locale_type,
2115 tag_set, exact_p,
2116 cl->add_meth_is_nil ?
2117 SPEC_REMOVE_LOCALE_TYPE :
2118 cl->add_meth);
2119 else
2120 specifier_copy_spec (specifier, cl->dest, locale, locale_type,
2121 tag_set, exact_p,
2122 cl->add_meth_is_nil ? SPEC_REMOVE_LOCALE :
2123 cl->add_meth);
2124 return 0;
2125 }
2126
2127 DEFUN ("copy-specifier", Fcopy_specifier, Scopy_specifier,
2128 1, 6, 0 /*
2129 Copy SPECIFIER to DEST, or create a new one if DEST is nil.
2130
2131 If DEST is nil or omitted, a new specifier will be created and the
2132 specifications copied into it. Otherwise, the specifications will be
2133 copied into the existing specifier in DEST.
2134
2135 If LOCALE is nil or 'all, all specifications will be copied. If LOCALE
2136 is a particular locale, the specification for that particular locale will
2137 be copied. If LOCALE is a locale type, the specifications for all locales
2138 of that type will be copied. LOCALE can also be a list of locales,
2139 locale types, and/or 'all; this is equivalent to calling `copy-specifier'
2140 for each of the elements of the list. See `specifier-spec-list' for more
2141 information about LOCALE.
2142
2143 Only instantiators where TAG-SET (a list of zero or more tags) is a
2144 subset of (or possibly equal to) the instantiator's tag set are copied.
2145 (The default value of nil is a subset of all tag sets, so in this case
2146 no instantiators will be screened out.) If EXACT-P is non-nil, however,
2147 TAG-SET must be equal to an instantiator's tag set for the instantiator
2148 to be copied.
2149
2150 Optional argument HOW-TO-ADD specifies what to do with existing
2151 specifications in DEST. If nil, then whichever locales or locale types
2152 are copied will first be completely erased in DEST. Otherwise, it is
2153 the same as in `add-spec-to-specifier'.
2154 */ )
2155 (specifier, dest, locale, tag_set, exact_p, how_to_add)
2156 Lisp_Object specifier, dest, locale, tag_set, exact_p, how_to_add;
2157 {
2158 struct gcpro gcpro1;
2159 struct copy_specifier_closure cl;
2160
2161 CHECK_SPECIFIER (specifier);
2162 if (NILP (how_to_add))
2163 cl.add_meth_is_nil = 1;
2164 else
2165 cl.add_meth_is_nil = 0;
2166 cl.add_meth = decode_how_to_add_specification (how_to_add);
2167 if (NILP (dest))
2168 {
2169 /* #### What about copying the extra data? */
2170 dest = make_specifier (XSPECIFIER (specifier)->methods);
2171 }
2172 else
2173 {
2174 CHECK_SPECIFIER (dest);
2175 if (XSPECIFIER (dest)->methods != XSPECIFIER (specifier)->methods)
2176 error ("Specifiers not of same type");
2177 }
2178
2179 cl.dest = dest;
2180 GCPRO1 (dest);
2181 map_specifier (specifier, locale, copy_specifier_mapfun,
2182 tag_set, exact_p, &cl);
2183 UNGCPRO;
2184 recompute_cached_specifier_everywhere (specifier);
2185 return dest;
2186 }
2187
2188
2189 /************************************************************************/
2190 /* Instancing */
2191 /************************************************************************/
2192
2193 static Lisp_Object
2194 call_validate_matchspec_method (Lisp_Object boxed_method,
2195 Lisp_Object matchspec)
2196 {
2197 ((void (*)(Lisp_Object)) get_opaque_ptr (boxed_method)) (matchspec);
2198 return Qt;
2199 }
2200
2201 static Lisp_Object
2202 check_valid_specifier_matchspec (Lisp_Object matchspec,
2203 struct specifier_methods *meths,
2204 Error_behavior errb)
2205 {
2206 if (meths->validate_matchspec_method)
2207 {
2208 Lisp_Object retval;
2209
2210 if (ERRB_EQ (errb, ERROR_ME))
2211 {
2212 (meths->validate_matchspec_method) (matchspec);
2213 retval = Qt;
2214 }
2215 else
2216 {
2217 Lisp_Object opaque =
2218 make_opaque_ptr ((void *) meths->validate_matchspec_method);
2219 struct gcpro gcpro1;
2220
2221 GCPRO1 (opaque);
2222 retval = call_with_suspended_errors (call_validate_matchspec_method,
2223 Qnil,
2224 Qspecifier, errb, 2,
2225 opaque, matchspec);
2226 free_opaque_ptr (opaque);
2227 UNGCPRO;
2228 }
2229
2230 return retval;
2231 }
2232 else
2233 {
2234 maybe_signal_simple_error
2235 ("Matchspecs not allowed for this specifier type",
2236 intern (meths->name), Qspecifier, errb);
2237 return Qnil;
2238 }
2239 }
2240
2241 DEFUN ("check-valid-specifier-matchspec", Fcheck_valid_specifier_matchspec,
2242 Scheck_valid_specifier_matchspec,
2243 2, 2, 0 /*
2244 Signal an error if MATCHSPEC is invalid for SPECIFIER-TYPE.
2245 See `specifier-matching-instance' for a description of matchspecs.
2246 */ )
2247 (matchspec, specifier_type)
2248 Lisp_Object matchspec, specifier_type;
2249 {
2250 struct specifier_methods *meths = decode_specifier_type (specifier_type,
2251 ERROR_ME);
2252
2253 return check_valid_specifier_matchspec (matchspec, meths, ERROR_ME);
2254 }
2255
2256 DEFUN ("valid-specifier-matchspec-p", Fvalid_specifier_matchspec_p,
2257 Svalid_specifier_matchspec_p,
2258 2, 2, 0 /*
2259 Return non-nil if MATCHSPEC is valid for SPECIFIER-TYPE.
2260 See `specifier-matching-instance' for a description of matchspecs.
2261 */ )
2262 (matchspec, specifier_type)
2263 Lisp_Object matchspec, specifier_type;
2264 {
2265 struct specifier_methods *meths = decode_specifier_type (specifier_type,
2266 ERROR_ME);
2267
2268 return check_valid_specifier_matchspec (matchspec, meths, ERROR_ME_NOT);
2269 }
2270
2271 /* This function is purposely not callable from Lisp. If a Lisp
2272 caller wants to set a fallback, they should just set the
2273 global value. */
2274
2275 void
2276 set_specifier_fallback (Lisp_Object specifier, Lisp_Object fallback)
2277 {
2278 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2279 assert (SPECIFIERP (fallback) ||
2280 !NILP (Fvalid_inst_list_p (fallback, Fspecifier_type (specifier))));
2281 if (SPECIFIERP (fallback))
2282 assert (EQ (Fspecifier_type (specifier), Fspecifier_type (fallback)));
2283 sp->fallback = fallback;
2284 /* call the after-change method */
2285 MAYBE_SPECMETH (sp, after_change, (specifier, Qfallback));
2286 recompute_cached_specifier_everywhere (specifier);
2287 }
2288
2289 DEFUN ("specifier-fallback", Fspecifier_fallback, Sspecifier_fallback,
2290 1, 1, 0 /*
2291 Return the fallback value for SPECIFIER.
2292 Fallback values are provided by the C code for certain built-in
2293 specifiers to make sure that instancing won't fail even if all
2294 specs are removed from the specifier, or to implement simple
2295 inheritance behavior (e.g. this method is used to ensure that
2296 faces other than 'default inherit their attributes from 'default).
2297 By design, you cannot change the fallback value, and specifiers
2298 created with `make-specifier' will never have a fallback (although
2299 a similar, Lisp-accessible capability may be provided in the future
2300 to allow for inheritance).
2301
2302 The fallback value will be an inst-list that is instanced like
2303 any other inst-list, a specifier of the same type as SPECIFIER
2304 \(results in inheritance), or nil for no fallback.
2305
2306 When you instance a specifier, you can explicitly request that the
2307 fallback not be consulted. (The C code does this, for example, when
2308 merging faces.) See `specifier-instance'.
2309 */ )
2310 (specifier)
2311 Lisp_Object specifier;
2312 {
2313 CHECK_SPECIFIER (specifier);
2314 return Fcopy_tree (XSPECIFIER (specifier)->fallback, Qt);
2315 }
2316
2317 static Lisp_Object
2318 specifier_instance_from_inst_list (Lisp_Object specifier,
2319 Lisp_Object matchspec,
2320 Lisp_Object domain,
2321 Lisp_Object inst_list,
2322 Error_behavior errb, int no_quit,
2323 Lisp_Object depth)
2324 {
2325 /* This function can GC */
2326 struct Lisp_Specifier *sp;
2327 Lisp_Object device;
2328 Lisp_Object rest;
2329 int count = specpdl_depth ();
2330 struct gcpro gcpro1, gcpro2;
2331
2332 GCPRO2 (specifier, inst_list);
2333
2334 sp = XSPECIFIER (specifier);
2335 device = DFW_DEVICE (domain);
2336
2337 if (no_quit)
2338 /* The instantiate method is allowed to call eval. Since it
2339 is quite common for this function to get called from somewhere in
2340 redisplay we need to make sure that quits are ignored. Otherwise
2341 Fsignal will abort. */
2342 specbind (Qinhibit_quit, Qt);
2343
2344 LIST_LOOP (rest, inst_list)
2345 {
2346 Lisp_Object tagged_inst = XCAR (rest);
2347 Lisp_Object tag_set = XCAR (tagged_inst);
2348
2349 if (device_matches_specifier_tag_set_p (device, tag_set))
2350 {
2351 Lisp_Object val = XCDR (tagged_inst);
2352
2353 if (HAS_SPECMETH_P (sp, instantiate))
2354 val = call_with_suspended_errors (RAW_SPECMETH (sp, instantiate),
2355 Qunbound, Qspecifier, errb,
2356 5, specifier, matchspec, domain,
2357 XCDR (tagged_inst),
2358 depth);
2359
2360 if (!UNBOUNDP (val))
2361 {
2362 unbind_to (count, Qnil);
2363 UNGCPRO;
2364 return val;
2365 }
2366 }
2367 }
2368
2369 unbind_to (count, Qnil);
2370 UNGCPRO;
2371 return Qunbound;
2372 }
2373
2374 /* Given a SPECIFIER and a DOMAIN, return a specific instance for that
2375 specifier. Try to find one by checking the specifier types from most
2376 specific (buffer) to most general (global). If we find an instance,
2377 return it. Otherwise return Qunbound. */
2378
2379 #define CHECK_INSTANCE_ENTRY(key, matchspec, type) \
2380 do { \
2381 Lisp_Object *__inst_list = \
2382 specifier_get_inst_list (specifier, key, type); \
2383 if (__inst_list) \
2384 { \
2385 Lisp_Object __val__ = \
2386 specifier_instance_from_inst_list (specifier, matchspec, \
2387 domain, *__inst_list, \
2388 errb, no_quit, depth); \
2389 if (!UNBOUNDP (__val__)) \
2390 return __val__; \
2391 } \
2392 } while (0)
2393
2394 /* We accept any window, frame or device domain and do our checking
2395 starting from as specific a locale type as we can determine from the
2396 domain we are passed and going on up through as many other locale types
2397 as we can determine. In practice, when called from redisplay the
2398 arg will usually be a window and occasionally a frame. If
2399 triggered by a user call, who knows what it will usually be. */
2400 Lisp_Object
2401 specifier_instance (Lisp_Object specifier, Lisp_Object matchspec,
2402 Lisp_Object domain, Error_behavior errb, int no_quit,
2403 int no_fallback, Lisp_Object depth)
2404 {
2405 Lisp_Object buffer = Qnil;
2406 Lisp_Object window = Qnil;
2407 Lisp_Object frame = Qnil;
2408 Lisp_Object device = Qnil;
2409 Lisp_Object tag = Qnil;
2410 struct device *d;
2411 struct Lisp_Specifier *sp;
2412
2413 sp = XSPECIFIER (specifier);
2414
2415 /* Attempt to determine buffer, window, frame, and device from the
2416 domain. */
2417 if (WINDOWP (domain))
2418 window = domain;
2419 else if (FRAMEP (domain))
2420 frame = domain;
2421 else if (DEVICEP (domain))
2422 device = domain;
2423 else
2424 abort ();
2425
2426 if (NILP (buffer) && !NILP (window))
2427 buffer = XWINDOW (window)->buffer;
2428 if (NILP (frame) && !NILP (window))
2429 frame = XWINDOW (window)->frame;
2430 if (NILP (device))
2431 /* frame had better exist; if device is undeterminable, something
2432 really went wrong. */
2433 device = XFRAME (frame)->device;
2434
2435 /* device had better be determined by now; abort if not. */
2436 d = XDEVICE (device);
2437 tag = DEVICE_CLASS (d);
2438
2439 depth = make_int (1 + XINT (depth));
2440 if (XINT (depth) > 20)
2441 {
2442 maybe_error (Qspecifier, errb, "Apparent loop in specifier inheritance");
2443 /* The specification is fucked; at least try the fallback
2444 (which better not be fucked, because it's not changeable
2445 from Lisp). */
2446 depth = Qzero;
2447 goto do_fallback;
2448 }
2449
2450 try_again:
2451 /* First see if we can generate one from the buffer specifiers. */
2452 if (!NILP (buffer))
2453 CHECK_INSTANCE_ENTRY (buffer, matchspec, LOCALE_BUFFER);
2454
2455 /* Next see if we can generate one from the window specifiers. */
2456 if (!NILP (window))
2457 CHECK_INSTANCE_ENTRY (window, matchspec, LOCALE_WINDOW);
2458
2459 /* Next see if we can generate one from the frame specifiers. */
2460 if (!NILP (frame))
2461 CHECK_INSTANCE_ENTRY (frame, matchspec, LOCALE_FRAME);
2462
2463 /* If we still haven't succeeded try with the device specifiers. */
2464 CHECK_INSTANCE_ENTRY (device, matchspec, LOCALE_DEVICE);
2465
2466 /* Last and least try the global specifiers. */
2467 CHECK_INSTANCE_ENTRY (Qglobal, matchspec, LOCALE_GLOBAL);
2468
2469 do_fallback:
2470 /* We're out of specifiers and we still haven't generated an
2471 instance. At least try the fallback ... If this fails,
2472 then we just return Qunbound. */
2473
2474 if (no_fallback || NILP (sp->fallback))
2475 /* I said, I don't want the fallbacks. */
2476 return Qunbound;
2477
2478 if (SPECIFIERP (sp->fallback))
2479 {
2480 /* If you introduced loops in the default specifier chain,
2481 then you're fucked, so you better not do this. */
2482 specifier = sp->fallback;
2483 sp = XSPECIFIER (specifier);
2484 goto try_again;
2485 }
2486
2487 assert (CONSP (sp->fallback));
2488 return specifier_instance_from_inst_list (specifier, matchspec, domain,
2489 sp->fallback, errb, no_quit,
2490 depth);
2491 }
2492 #undef CHECK_INSTANCE_ENTRY
2493
2494 Lisp_Object
2495 specifier_instance_no_quit (Lisp_Object specifier, Lisp_Object matchspec,
2496 Lisp_Object domain, Error_behavior errb,
2497 int no_fallback, Lisp_Object depth)
2498 {
2499 return specifier_instance (specifier, matchspec, domain, errb,
2500 1, no_fallback, depth);
2501 }
2502
2503 DEFUN ("specifier-instance", Fspecifier_instance, Sspecifier_instance,
2504 1, 4, 0 /*
2505 Instantiate SPECIFIER (return its value) in DOMAIN.
2506 If no instance can be generated for this domain, return DEFAULT.
2507
2508 DOMAIN should be a window, frame, or device. Other values that are legal
2509 as a locale (e.g. a buffer) are not valid as a domain because they do not
2510 provide enough information to identify a particular device (see
2511 `valid-specifier-domain-p'). DOMAIN defaults to the selected window
2512 if omitted.
2513
2514 \"Instantiating\" a specifier in a particular domain means determining
2515 the specifier's \"value\" in that domain. This is accomplished by
2516 searching through the specifications in the specifier that correspond
2517 to all locales that can be derived from the given domain, from specific
2518 to general. In most cases, the domain is an Emacs window. In that case
2519 specifications are searched for as follows:
2520
2521 1. A specification whose locale is the window's buffer;
2522 2. A specification whose locale is the window itself;
2523 3. A specification whose locale is the window's frame;
2524 4. A specification whose locale is the window's frame's device;
2525 5. A specification whose locale is 'global.
2526
2527 If all of those fail, then the C-code-provided fallback value for
2528 this specifier is consulted (see `specifier-fallback'). If it is
2529 an inst-list, then this function attempts to instantiate that list
2530 just as when a specification is located in the first five steps above.
2531 If the fallback is a specifier, `specifier-instance' is called
2532 recursively on this specifier and the return value used. Note,
2533 however, that if the optional argument NO-FALLBACK is non-nil,
2534 the fallback value will not be consulted.
2535
2536 Note that there may be more than one specification matching a particular
2537 locale; all such specifications are considered before looking for any
2538 specifications for more general locales. Any particular specification
2539 that is found may be rejected because its tag set does not match the
2540 device being instantiated over, or because the specification is not
2541 valid for the device of the given domain (e.g. the font or color name
2542 does not exist for this particular X server).
2543
2544 The returned value is dependent on the type of specifier. For example,
2545 for a font specifier (as returned by the `face-font' function), the returned
2546 value will be a font-instance object. For glyphs, the returned value
2547 will be a string, pixmap, or subwindow.
2548
2549 See also `specifier-matching-instance'.
2550 */ )
2551 (specifier, domain, defalt, no_fallback)
2552 Lisp_Object specifier, domain, defalt, no_fallback;
2553 {
2554 Lisp_Object instance;
2555
2556 CHECK_SPECIFIER (specifier);
2557 domain = decode_domain (domain);
2558
2559 instance = specifier_instance (specifier, Qunbound, domain, ERROR_ME, 0,
2560 !NILP (no_fallback), Qzero);
2561 if (UNBOUNDP (instance))
2562 return defalt;
2563 return instance;
2564 }
2565
2566 DEFUN ("specifier-matching-instance", Fspecifier_matching_instance,
2567 Sspecifier_matching_instance, 2, 5, 0 /*
2568 Return an instance for SPECIFIER in DOMAIN that matches MATCHSPEC.
2569 If no instance can be generated for this domain, return DEFAULT.
2570
2571 This function is identical to `specifier-instance' except that a
2572 specification will only be considered if it matches MATCHSPEC.
2573 The definition of \"match\", and allowed values for MATCHSPEC, are
2574 dependent on the particular type of specifier. Here are some examples:
2575
2576 -- For chartable (e.g. display table) specifiers, MATCHSPEC should be a
2577 character, and the specification (a chartable) must give a value for
2578 that character in order to be considered. This allows you to specify,
2579 e.g., a buffer-local display table that only gives values for particular
2580 characters. All other characters are handled as if the buffer-local
2581 display table is not there. (Chartable specifiers are not yet
2582 implemented.)
2583
2584 -- For font specifiers, MATCHSPEC should be a charset, and the specification
2585 (a font string) must have a registry that matches the charset's registry.
2586 (This only makes sense with Mule support.) This makes it easy to choose a
2587 font that can display a particular character. (This is what redisplay
2588 does, in fact.)
2589 */ )
2590 (specifier, matchspec, domain, defalt, no_fallback)
2591 Lisp_Object specifier, matchspec, domain, defalt, no_fallback;
2592 {
2593 Lisp_Object instance;
2594
2595 CHECK_SPECIFIER (specifier);
2596 check_valid_specifier_matchspec (matchspec, XSPECIFIER (specifier)->methods,
2597 ERROR_ME);
2598 domain = decode_domain (domain);
2599
2600 instance = specifier_instance (specifier, matchspec, domain, ERROR_ME, 0,
2601 !NILP (no_fallback), Qzero);
2602 if (UNBOUNDP (instance))
2603 return defalt;
2604 return instance;
2605 }
2606
2607 DEFUN ("specifier-instance-from-inst-list", Fspecifier_instance_from_inst_list,
2608 Sspecifier_instance_from_inst_list, 3, 4, 0 /*
2609 Attempt to convert a particular inst-list into an instance.
2610 This attempts to instantiate INST-LIST in the given DOMAIN,
2611 as if INST-LIST existed in a specification in SPECIFIER. If
2612 the instantiation fails, DEFAULT is returned. In most circumstances,
2613 you should not use this function; use `specifier-instance' instead.
2614 */ )
2615 (specifier, domain, inst_list, defalt)
2616 Lisp_Object specifier, domain, inst_list, defalt;
2617 {
2618 Lisp_Object val = Qunbound;
2619 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2620 struct gcpro gcpro1;
2621 Lisp_Object built_up_list = Qnil;
2622
2623 CHECK_SPECIFIER (specifier);
2624 check_valid_domain (domain);
2625 check_valid_inst_list (inst_list, sp->methods, ERROR_ME);
2626 GCPRO1 (built_up_list);
2627 built_up_list = build_up_processed_list (specifier, domain, inst_list);
2628 if (!NILP (built_up_list))
2629 val = specifier_instance_from_inst_list (specifier, Qunbound, domain,
2630 built_up_list, ERROR_ME, 0,
2631 Qzero);
2632 UNGCPRO;
2633 if (UNBOUNDP (val))
2634 return defalt;
2635 return val;
2636 }
2637
2638 DEFUN ("specifier-matching-instance-from-inst-list",
2639 Fspecifier_matching_instance_from_inst_list,
2640 Sspecifier_matching_instance_from_inst_list, 4, 5, 0 /*
2641 Attempt to convert a particular inst-list into an instance.
2642 This attempts to instantiate INST-LIST in the given DOMAIN
2643 (as if INST-LIST existed in a specification in SPECIFIER),
2644 matching the specifications against MATCHSPEC.
2645
2646 This function is analogous to `specifier-instance-from-inst-list'
2647 but allows for specification-matching as in `specifier-matching-instance'.
2648 See that function for a description of exactly how the matching process
2649 works.
2650 */ )
2651 (specifier, matchspec, domain, inst_list, defalt)
2652 Lisp_Object specifier, matchspec, domain, inst_list, defalt;
2653 {
2654 Lisp_Object val = Qunbound;
2655 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2656 struct gcpro gcpro1;
2657 Lisp_Object built_up_list = Qnil;
2658
2659 CHECK_SPECIFIER (specifier);
2660 check_valid_specifier_matchspec (matchspec, XSPECIFIER (specifier)->methods,
2661 ERROR_ME);
2662 check_valid_domain (domain);
2663 check_valid_inst_list (inst_list, sp->methods, ERROR_ME);
2664 GCPRO1 (built_up_list);
2665 built_up_list = build_up_processed_list (specifier, domain, inst_list);
2666 if (!NILP (built_up_list))
2667 val = specifier_instance_from_inst_list (specifier, matchspec, domain,
2668 built_up_list, ERROR_ME, 0,
2669 Qzero);
2670 UNGCPRO;
2671 if (UNBOUNDP (val))
2672 return defalt;
2673 return val;
2674 }
2675
2676
2677 /************************************************************************/
2678 /* Caching in the struct window or frame */
2679 /************************************************************************/
2680
2681 /* Either STRUCT_WINDOW_OFFSET or STRUCT_FRAME_OFFSET can be 0 to indicate
2682 no caching in that sort of object. */
2683
2684 /* #### It would be nice if the specifier caching automatically knew
2685 about specifier fallbacks, so we didn't have to do it ourselves. */
2686
2687 void
2688 set_specifier_caching (Lisp_Object specifier, int struct_window_offset,
2689 void (*value_changed_in_window)
2690 (Lisp_Object specifier, struct window *w,
2691 Lisp_Object oldval),
2692 int struct_frame_offset,
2693 void (*value_changed_in_frame)
2694 (Lisp_Object specifier, struct frame *f,
2695 Lisp_Object oldval))
2696 {
2697 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2698
2699 if (!sp->caching)
2700 sp->caching = malloc_type_and_zero (struct specifier_caching);
2701 sp->caching->offset_into_struct_window = struct_window_offset;
2702 sp->caching->value_changed_in_window = value_changed_in_window;
2703 sp->caching->offset_into_struct_frame = struct_frame_offset;
2704 sp->caching->value_changed_in_frame = value_changed_in_frame;
2705 Vcached_specifiers = Fcons (specifier, Vcached_specifiers);
2706 recompute_cached_specifier_everywhere (specifier);
2707 }
2708
2709 static void
2710 recompute_one_cached_specifier_in_window (Lisp_Object specifier,
2711 struct window *w)
2712 {
2713 Lisp_Object window = Qnil;
2714 Lisp_Object newval, *location;
2715
2716 XSETWINDOW (window, w);
2717
2718 newval = specifier_instance (specifier, Qunbound, window, ERROR_ME_WARN,
2719 0, 0, Qzero);
2720 /* If newval ended up Qunbound, then the calling functions
2721 better be able to deal. If not, set a default so this
2722 never happens or correct it in the value_changed_in_window
2723 method. */
2724 location = (Lisp_Object *)
2725 ((char *) w + XSPECIFIER (specifier)->caching->offset_into_struct_window);
2726 if (!EQ (newval, *location))
2727 {
2728 Lisp_Object oldval = *location;
2729 *location = newval;
2730 (XSPECIFIER (specifier)->caching->value_changed_in_window)
2731 (specifier, w, oldval);
2732 }
2733 }
2734
2735 static void
2736 recompute_one_cached_specifier_in_frame (Lisp_Object specifier,
2737 struct frame *f)
2738 {
2739 Lisp_Object frame = Qnil;
2740 Lisp_Object newval, *location;
2741
2742 XSETFRAME (frame, f);
2743
2744 newval = specifier_instance (specifier, Qunbound, frame, ERROR_ME_WARN,
2745 0, 0, Qzero);
2746 /* If newval ended up Qunbound, then the calling functions
2747 better be able to deal. If not, set a default so this
2748 never happens or correct it in the value_changed_in_frame
2749 method. */
2750 location = (Lisp_Object *)
2751 ((char *) f + XSPECIFIER (specifier)->caching->offset_into_struct_frame);
2752 if (!EQ (newval, *location))
2753 {
2754 Lisp_Object oldval = *location;
2755 *location = newval;
2756 (XSPECIFIER (specifier)->caching->value_changed_in_frame)
2757 (specifier, f, oldval);
2758 }
2759 }
2760
2761 void
2762 recompute_all_cached_specifiers_in_window (struct window *w)
2763 {
2764 Lisp_Object rest;
2765
2766 LIST_LOOP (rest, Vcached_specifiers)
2767 {
2768 Lisp_Object specifier = XCAR (rest);
2769 if (XSPECIFIER (specifier)->caching->offset_into_struct_window)
2770 recompute_one_cached_specifier_in_window (specifier, w);
2771 }
2772 }
2773
2774 void
2775 recompute_all_cached_specifiers_in_frame (struct frame *f)
2776 {
2777 Lisp_Object rest;
2778
2779 LIST_LOOP (rest, Vcached_specifiers)
2780 {
2781 Lisp_Object specifier = XCAR (rest);
2782 if (XSPECIFIER (specifier)->caching->offset_into_struct_frame)
2783 recompute_one_cached_specifier_in_frame (specifier, f);
2784 }
2785 }
2786
2787 static int
2788 recompute_cached_specifier_everywhere_mapfun (struct window *w,
2789 void *closure)
2790 {
2791 Lisp_Object specifier = Qnil;
2792
2793 VOID_TO_LISP (specifier, closure);
2794 recompute_one_cached_specifier_in_window (specifier, w);
2795 return 0;
2796 }
2797
2798 static void
2799 recompute_cached_specifier_everywhere (Lisp_Object specifier)
2800 {
2801 Lisp_Object frmcons, devcons, concons;
2802
2803 if (!XSPECIFIER (specifier)->caching)
2804 return;
2805
2806 if (XSPECIFIER (specifier)->caching->offset_into_struct_window)
2807 {
2808 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
2809 map_windows (XFRAME (XCAR (frmcons)),
2810 recompute_cached_specifier_everywhere_mapfun,
2811 LISP_TO_VOID (specifier));
2812 }
2813
2814 if (XSPECIFIER (specifier)->caching->offset_into_struct_frame)
2815 {
2816 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
2817 recompute_one_cached_specifier_in_frame (specifier,
2818 XFRAME (XCAR (frmcons)));
2819 }
2820 }
2821
2822 DEFUN ("set-specifier-dirty-flag", Fset_specifier_dirty_flag,
2823 Sset_specifier_dirty_flag, 1, 1, 0 /*
2824 Force recomputation of any caches associated with SPECIFIER.
2825 Note that this automatically happens whenever you change a specification
2826 in SPECIFIER; you do not have to call this function then.
2827 One example of where this function is useful is when you have a
2828 toolbar button whose `active-p' field is an expression to be
2829 evaluated. Calling `set-specifier-dirty-flag' on the
2830 toolbar specifier will force the `active-p' fields to be
2831 recomputed.
2832 */ )
2833 (specifier)
2834 Lisp_Object specifier;
2835 {
2836 CHECK_SPECIFIER (specifier);
2837 recompute_cached_specifier_everywhere (specifier);
2838 return Qnil;
2839 }
2840
2841
2842 /************************************************************************/
2843 /* Generic specifier type */
2844 /************************************************************************/
2845
2846 DEFINE_SPECIFIER_TYPE (generic);
2847
2848 #if 0
2849
2850 /* This is the string that used to be in `generic-specifier-p'.
2851 The idea is good, but it doesn't quite work in the form it's
2852 in. (One major problem is that validating an instantiator
2853 is supposed to require only that the specifier type is passed,
2854 while with this approach the actual specifier is needed.)
2855
2856 What really needs to be done is to write a function
2857 `make-specifier-type' that creates new specifier types.
2858 #### I'll look into this for 19.14.
2859 */
2860
2861 "A generic specifier is a generalized kind of specifier with user-defined\n"
2862 "semantics. The instantiator can be any kind of Lisp object, and the\n"
2863 "instance computed from it is likewise any kind of Lisp object. The\n"
2864 "SPECIFIER-DATA should be an alist of methods governing how the specifier\n"
2865 "works. All methods are optional, and reasonable default methods will be\n"
2866 "provided. Currently there are two defined methods: 'instantiate and\n"
2867 "'validate.\n"
2868 "\n"
2869 "'instantiate specifies how to do the instantiation; if omitted, the\n"
2870 "instantiator itself is simply returned as the instance. The method\n"
2871 "should be a function that accepts three parameters (a specifier, the\n"
2872 "instantiator that matched the domain being instantiated over, and that\n"
2873 "domain), and should return a one-element list containing the instance,\n"
2874 "or nil if no instance exists. Note that the domain passed to this function\n"
2875 "is the domain being instantiated over, which may not be the same as the\n"
2876 "locale contained in the specification corresponding to the instantiator\n"
2877 "(for example, the domain being instantiated over could be a window, but\n"
2878 "the locale corresponding to the passed instantiator could be the window's\n"
2879 "buffer or frame).\n"
2880 "\n"
2881 "'validate specifies whether a given instantiator is valid; if omitted,\n"
2882 "all instantiators are considered valid. It should be a function of\n"
2883 "two arguments: an instantiator and a flag CAN-SIGNAL-ERROR. If this\n"
2884 "flag is false, the function must simply return t or nil indicating\n"
2885 "whether the instantiator is valid. If this flag is true, the function\n"
2886 "is free to signal an error if it encounters an invalid instantiator\n"
2887 "(this can be useful for issuing a specific error about exactly why the\n"
2888 "instantiator is valid). It can also return nil to indicate an invalid\n"
2889 "instantiator; in this case, a general error will be signalled."
2890
2891 #endif /* 0 */
2892
2893 DEFUN ("generic-specifier-p", Fgeneric_specifier_p,
2894 Sgeneric_specifier_p, 1, 1, 0 /*
2895 Return non-nil if OBJECT is a generic specifier.
2896
2897 A generic specifier allows any kind of Lisp object as an instantiator,
2898 and returns back the Lisp object unchanged when it is instantiated.
2899 */ )
2900 (object)
2901 Lisp_Object object;
2902 {
2903 return (GENERIC_SPECIFIERP (object) ? Qt : Qnil);
2904 }
2905
2906
2907 /************************************************************************/
2908 /* Integer specifier type */
2909 /************************************************************************/
2910
2911 DEFINE_SPECIFIER_TYPE (integer);
2912
2913 static void
2914 integer_validate (Lisp_Object instantiator)
2915 {
2916 CHECK_INT (instantiator);
2917 }
2918
2919 DEFUN ("integer-specifier-p", Finteger_specifier_p,
2920 Sinteger_specifier_p, 1, 1, 0 /*
2921 Return non-nil if OBJECT is an integer specifier.
2922 */ )
2923 (object)
2924 Lisp_Object object;
2925 {
2926 return (INTEGER_SPECIFIERP (object) ? Qt : Qnil);
2927 }
2928
2929 /************************************************************************/
2930 /* Non-negative-integer specifier type */
2931 /************************************************************************/
2932
2933 DEFINE_SPECIFIER_TYPE (natnum);
2934
2935 static void
2936 natnum_validate (Lisp_Object instantiator)
2937 {
2938 CHECK_NATNUM (instantiator);
2939 }
2940
2941 DEFUN ("natnum-specifier-p", Fnatnum_specifier_p,
2942 Snatnum_specifier_p, 1, 1, 0 /*
2943 Return non-nil if OBJECT is a natnum (non-negative-integer) specifier.
2944 */ )
2945 (object)
2946 Lisp_Object object;
2947 {
2948 return (NATNUM_SPECIFIERP (object) ? Qt : Qnil);
2949 }
2950
2951 /************************************************************************/
2952 /* Boolean specifier type */
2953 /************************************************************************/
2954
2955 DEFINE_SPECIFIER_TYPE (boolean);
2956
2957 static void
2958 boolean_validate (Lisp_Object instantiator)
2959 {
2960 if (!EQ (instantiator, Qt) && !EQ (instantiator, Qnil))
2961 signal_simple_error ("Must be t or nil", instantiator);
2962 }
2963
2964 DEFUN ("boolean-specifier-p", Fboolean_specifier_p,
2965 Sboolean_specifier_p, 1, 1, 0 /*
2966 Return non-nil if OBJECT is an boolean specifier.
2967 */ )
2968 (object)
2969 Lisp_Object object;
2970 {
2971 return (BOOLEAN_SPECIFIERP (object) ? Qt : Qnil);
2972 }
2973
2974
2975 /************************************************************************/
2976 /* Initialization */
2977 /************************************************************************/
2978
2979 void
2980 syms_of_specifier (void)
2981 {
2982 defsymbol (&Qspecifierp, "specifierp");
2983
2984 defsymbol (&Qconsole_type, "console-type");
2985 defsymbol (&Qdevice_class, "device-class");
2986
2987 /* Qinteger, Qboolean, Qgeneric defined in general.c */
2988 defsymbol (&Qnatnum, "natnum");
2989
2990 defsubr (&Svalid_specifier_type_p);
2991 defsubr (&Sspecifier_type_list);
2992 defsubr (&Smake_specifier);
2993 defsubr (&Sspecifierp);
2994 defsubr (&Sspecifier_type);
2995
2996 defsubr (&Svalid_specifier_locale_p);
2997 defsubr (&Svalid_specifier_domain_p);
2998 defsubr (&Svalid_specifier_locale_type_p);
2999 defsubr (&Sspecifier_locale_type_from_locale);
3000
3001 defsubr (&Svalid_specifier_tag_p);
3002 defsubr (&Svalid_specifier_tag_set_p);
3003 defsubr (&Scanonicalize_tag_set);
3004 defsubr (&Sdevice_matches_specifier_tag_set_p);
3005 defsubr (&Sdefine_specifier_tag);
3006 defsubr (&Sdevice_matching_specifier_tag_list);
3007 defsubr (&Sspecifier_tag_list);
3008 defsubr (&Sspecifier_tag_predicate);
3009
3010 defsubr (&Scheck_valid_instantiator);
3011 defsubr (&Svalid_instantiator_p);
3012 defsubr (&Scheck_valid_inst_list);
3013 defsubr (&Svalid_inst_list_p);
3014 defsubr (&Scheck_valid_spec_list);
3015 defsubr (&Svalid_spec_list_p);
3016 defsubr (&Sadd_spec_to_specifier);
3017 defsubr (&Sadd_spec_list_to_specifier);
3018 defsubr (&Sspecifier_spec_list);
3019 defsubr (&Sspecifier_specs);
3020 defsubr (&Sremove_specifier);
3021 defsubr (&Scopy_specifier);
3022
3023 defsubr (&Scheck_valid_specifier_matchspec);
3024 defsubr (&Svalid_specifier_matchspec_p);
3025 defsubr (&Sspecifier_fallback);
3026 defsubr (&Sspecifier_instance);
3027 defsubr (&Sspecifier_matching_instance);
3028 defsubr (&Sspecifier_instance_from_inst_list);
3029 defsubr (&Sspecifier_matching_instance_from_inst_list);
3030 defsubr (&Sset_specifier_dirty_flag);
3031
3032 defsubr (&Sgeneric_specifier_p);
3033 defsubr (&Sinteger_specifier_p);
3034 defsubr (&Snatnum_specifier_p);
3035 defsubr (&Sboolean_specifier_p);
3036
3037 /* Symbols pertaining to specifier creation. Specifiers are created
3038 in the syms_of() functions. */
3039
3040 /* locales are defined in general.c. */
3041
3042 defsymbol (&Qprepend, "prepend");
3043 defsymbol (&Qappend, "append");
3044 defsymbol (&Qremove_tag_set_prepend, "remove-tag-set-prepend");
3045 defsymbol (&Qremove_tag_set_append, "remove-tag-set-append");
3046 defsymbol (&Qremove_locale, "remove-locale");
3047 defsymbol (&Qremove_locale_type, "remove-locale-type");
3048 defsymbol (&Qremove_all, "remove-all");
3049
3050 defsymbol (&Qfallback, "fallback");
3051 }
3052
3053 void
3054 specifier_type_create (void)
3055 {
3056 the_specifier_type_entry_dynarr = Dynarr_new (struct specifier_type_entry);
3057
3058 Vspecifier_type_list = Qnil;
3059 staticpro (&Vspecifier_type_list);
3060
3061 INITIALIZE_SPECIFIER_TYPE (generic, "generic", "generic-specifier-p");
3062
3063 INITIALIZE_SPECIFIER_TYPE (integer, "integer", "integer-specifier-p");
3064
3065 SPECIFIER_HAS_METHOD (integer, validate);
3066
3067 INITIALIZE_SPECIFIER_TYPE (natnum, "natnum", "natnum-specifier-p");
3068
3069 SPECIFIER_HAS_METHOD (natnum, validate);
3070
3071 INITIALIZE_SPECIFIER_TYPE (boolean, "boolean", "boolean-specifier-p");
3072
3073 SPECIFIER_HAS_METHOD (boolean, validate);
3074 }
3075
3076 void
3077 vars_of_specifier (void)
3078 {
3079 Vcached_specifiers = Qnil;
3080 staticpro (&Vcached_specifiers);
3081
3082 /* Do NOT mark through this, or specifiers will never be GC'd.
3083 This is the same deal as for weak hashtables. */
3084 Vall_specifiers = Qnil;
3085
3086 Vuser_defined_tags = Qnil;
3087 staticpro (&Vuser_defined_tags);
3088 }