comparison src/specifier.c @ 3659:98af8a976fc3

[xemacs-hg @ 2006-11-05 22:31:31 by aidan] Support specifying fonts for particular character sets in Mule; support translation to ISO 10646-1 for Mule character sets without an otherwise matching font; move to a vector of X11-charset-X11-registry instead of a regex for the charset-registry property.
author aidan
date Sun, 05 Nov 2006 22:31:46 +0000
parents d674024a8674
children b880e45ea63b
comparison
equal deleted inserted replaced
3658:0db1aaedbbef 3659:98af8a976fc3
45 Lisp_Object Qremove_locale, Qremove_locale_type; 45 Lisp_Object Qremove_locale, Qremove_locale_type;
46 46
47 Lisp_Object Qconsole_type, Qdevice_class; 47 Lisp_Object Qconsole_type, Qdevice_class;
48 48
49 static Lisp_Object Vuser_defined_tags; 49 static Lisp_Object Vuser_defined_tags;
50 static Lisp_Object Vcharset_tag_lists;
50 51
51 typedef struct specifier_type_entry specifier_type_entry; 52 typedef struct specifier_type_entry specifier_type_entry;
52 struct specifier_type_entry 53 struct specifier_type_entry
53 { 54 {
54 Lisp_Object symbol; 55 Lisp_Object symbol;
426 { specifier_extra_description_map } }, 427 { specifier_extra_description_map } },
427 { XD_END } 428 { XD_END }
428 }; 429 };
429 430
430 static const struct memory_description specifier_empty_extra_description_1[] = 431 static const struct memory_description specifier_empty_extra_description_1[] =
431 { 432 {
432 { XD_END } 433 { XD_END }
433 }; 434 };
434 435
435 const struct sized_memory_description specifier_empty_extra_description = { 436 const struct sized_memory_description specifier_empty_extra_description = {
436 0, specifier_empty_extra_description_1 437 0, specifier_empty_extra_description_1
437 }; 438 };
438 439
469 if (EQ (type, Dynarr_at (the_specifier_type_entry_dynarr, i).symbol)) 470 if (EQ (type, Dynarr_at (the_specifier_type_entry_dynarr, i).symbol))
470 return Dynarr_at (the_specifier_type_entry_dynarr, i).meths; 471 return Dynarr_at (the_specifier_type_entry_dynarr, i).meths;
471 } 472 }
472 473
473 maybe_invalid_argument ("Invalid specifier type", 474 maybe_invalid_argument ("Invalid specifier type",
474 type, Qspecifier, errb); 475 type, Qspecifier, errb);
475 476
476 return 0; 477 return 0;
477 } 478 }
478 479
479 static int 480 static int
681 value in that domain). Valid domains are image instances, windows, frames, 682 value in that domain). Valid domains are image instances, windows, frames,
682 and devices. \(nil is not valid.) image instances are pseudo-domains since 683 and devices. \(nil is not valid.) image instances are pseudo-domains since
683 instantiation will actually occur in the window the image instance itself is 684 instantiation will actually occur in the window the image instance itself is
684 instantiated in. 685 instantiated in.
685 */ 686 */
686 (domain)) 687 (domain))
687 { 688 {
688 /* This cannot GC. */ 689 /* This cannot GC. */
689 return ((DEVICEP (domain) && DEVICE_LIVE_P (XDEVICE (domain))) || 690 return ((DEVICEP (domain) && DEVICE_LIVE_P (XDEVICE (domain))) ||
690 (FRAMEP (domain) && FRAME_LIVE_P (XFRAME (domain))) || 691 (FRAMEP (domain) && FRAME_LIVE_P (XFRAME (domain))) ||
691 (WINDOWP (domain) && WINDOW_LIVE_P (XWINDOW (domain))) || 692 (WINDOWP (domain) && WINDOW_LIVE_P (XWINDOW (domain))) ||
692 /* #### get image instances out of domains! */ 693 /* #### get image instances out of domains! */
693 IMAGE_INSTANCEP (domain)) 694 IMAGE_INSTANCEP (domain))
694 ? Qt : Qnil; 695 ? Qt : Qnil;
695 } 696 }
696 697
697 DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1, 1, 0, 698 DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1,
698 /* 699 1, 0, /*
699 Given a specifier LOCALE-TYPE, return non-nil if it is valid. 700 Given a specifier LOCALE-TYPE, return non-nil if it is valid.
700 Valid locale types are `global', `device', `frame', `window', and `buffer'. 701 Valid locale types are `global', `device', `frame', `window', and `buffer'.
701 \(Note, however, that in functions that accept either a locale or a locale 702 \(Note, however, that in functions that accept either a locale or a locale
702 type, `global' is considered an individual locale.) 703 type, `global' is considered an individual locale.)
703 */ 704 */
704 (locale_type)) 705 (locale_type))
705 { 706 {
706 /* This cannot GC. */ 707 /* This cannot GC. */
707 return (EQ (locale_type, Qglobal) || 708 return (EQ (locale_type, Qglobal) ||
708 EQ (locale_type, Qdevice) || 709 EQ (locale_type, Qdevice) ||
709 EQ (locale_type, Qframe) || 710 EQ (locale_type, Qframe) ||
729 (locale)) 730 (locale))
730 { 731 {
731 /* This cannot GC. */ 732 /* This cannot GC. */
732 if (NILP (Fvalid_specifier_locale_p (locale))) 733 if (NILP (Fvalid_specifier_locale_p (locale)))
733 invalid_argument ("Invalid specifier locale", 734 invalid_argument ("Invalid specifier locale",
734 locale); 735 locale);
735 if (DEVICEP (locale)) return Qdevice; 736 if (DEVICEP (locale)) return Qdevice;
736 if (FRAMEP (locale)) return Qframe; 737 if (FRAMEP (locale)) return Qframe;
737 if (WINDOWP (locale)) return Qwindow; 738 if (WINDOWP (locale)) return Qwindow;
738 if (BUFFERP (locale)) return Qbuffer; 739 if (BUFFERP (locale)) return Qbuffer;
739 assert (EQ (locale, Qglobal)); 740 assert (EQ (locale, Qglobal));
748 return Qglobal; 749 return Qglobal;
749 else if (!NILP (Fvalid_specifier_locale_p (locale))) 750 else if (!NILP (Fvalid_specifier_locale_p (locale)))
750 return locale; 751 return locale;
751 else 752 else
752 invalid_argument ("Invalid specifier locale", 753 invalid_argument ("Invalid specifier locale",
753 locale); 754 locale);
754 755
755 return Qnil; 756 return Qnil;
756 } 757 }
757 758
758 static enum spec_locale_type 759 static enum spec_locale_type
764 if (EQ (locale_type, Qframe)) return LOCALE_FRAME; 765 if (EQ (locale_type, Qframe)) return LOCALE_FRAME;
765 if (EQ (locale_type, Qwindow)) return LOCALE_WINDOW; 766 if (EQ (locale_type, Qwindow)) return LOCALE_WINDOW;
766 if (EQ (locale_type, Qbuffer)) return LOCALE_BUFFER; 767 if (EQ (locale_type, Qbuffer)) return LOCALE_BUFFER;
767 768
768 invalid_argument ("Invalid specifier locale type", 769 invalid_argument ("Invalid specifier locale type",
769 locale_type); 770 locale_type);
770 RETURN_NOT_REACHED (LOCALE_GLOBAL); 771 RETURN_NOT_REACHED (LOCALE_GLOBAL);
771 } 772 }
772 773
773 Lisp_Object 774 Lisp_Object
774 decode_locale_list (Lisp_Object locale) 775 decode_locale_list (Lisp_Object locale)
801 static void 802 static void
802 check_valid_domain (Lisp_Object domain) 803 check_valid_domain (Lisp_Object domain)
803 { 804 {
804 if (NILP (Fvalid_specifier_domain_p (domain))) 805 if (NILP (Fvalid_specifier_domain_p (domain)))
805 invalid_argument ("Invalid specifier domain", 806 invalid_argument ("Invalid specifier domain",
806 domain); 807 domain);
807 } 808 }
808 809
809 Lisp_Object 810 Lisp_Object
810 decode_domain (Lisp_Object domain) 811 decode_domain (Lisp_Object domain)
811 { 812 {
832 } 833 }
833 834
834 DEFUN ("valid-specifier-tag-set-p", Fvalid_specifier_tag_set_p, 1, 1, 0, /* 835 DEFUN ("valid-specifier-tag-set-p", Fvalid_specifier_tag_set_p, 1, 1, 0, /*
835 Return non-nil if TAG-SET is a valid specifier tag set. 836 Return non-nil if TAG-SET is a valid specifier tag set.
836 837
837 A specifier tag set is an entity that is attached to an instantiator 838 A specifier tag set is an entity that is attached to an instantiator and can
838 and can be used to restrict the scope of that instantiator to a 839 be used to restrict the scope of that instantiator to a particular device
839 particular device class or device type and/or to mark instantiators 840 class, device type, or charset. It can also be used to mark instantiators
840 added by a particular package so that they can be later removed. 841 added by a particular package so that they can be later removed as a group.
841 842
842 A specifier tag set consists of a list of zero of more specifier tags, 843 A specifier tag set consists of a list of zero of more specifier tags,
843 each of which is a symbol that is recognized by XEmacs as a tag. 844 each of which is a symbol that is recognized by XEmacs as a tag.
844 \(The valid device types and device classes are always tags, as are 845 \(The valid device types and device classes are always tags, as are
845 any tags defined by `define-specifier-tag'.) It is called a "tag set" 846 any tags defined by `define-specifier-tag'.) It is called a "tag set"
846 \(as opposed to a list) because the order of the tags or the number of 847 \(as opposed to a list) because the order of the tags or the number of
847 times a particular tag occurs does not matter. 848 times a particular tag occurs does not matter.
848 849
849 Each tag has a predicate associated with it, which specifies whether 850 Each tag has two predicates associated with it, which specify, respectively,
850 that tag applies to a particular device. The tags which are device types 851 whether that tag applies to a particular device and whether it applies to a
851 and classes match devices of that type or class. User-defined tags can 852 particular character set. The predefined tags which are device types and
852 have any predicate, or none (meaning that all devices match). When 853 classes match devices of that type or class. User-defined tags can have any
853 attempting to instantiate a specifier, a particular instantiator is only 854 device predicate, or none (meaning that all devices match). When attempting
854 considered if the device of the domain being instantiated over matches 855 to instantiate a specifier, a particular instantiator is only considered if
855 all tags in the tag set attached to that instantiator. 856 the device of the domain being instantiated over matches all tags in the tag
857 set attached to that instantiator.
858
859 If a charset is to be considered--which is only the case for face
860 instantiators--this consideration may be done twice. The first iteration
861 pays attention to the character set predicates; if no instantiator can be
862 found in that case, the search is repeated ignoring the character set
863 predicates.
856 864
857 Most of the time, a tag set is not specified, and the instantiator 865 Most of the time, a tag set is not specified, and the instantiator
858 gets a null tag set, which matches all devices. 866 gets a null tag set, which matches all devices.
859 */ 867 */
860 (tag_set)) 868 (tag_set))
861 { 869 {
862 Lisp_Object rest; 870 Lisp_Object rest;
863 871
864 for (rest = tag_set; !NILP (rest); rest = XCDR (rest)) 872 for (rest = tag_set; !NILP (rest); rest = XCDR (rest))
865 { 873 {
878 /* The return value of this function must be GCPRO'd. */ 886 /* The return value of this function must be GCPRO'd. */
879 if (!NILP (Fvalid_specifier_tag_p (tag_set))) 887 if (!NILP (Fvalid_specifier_tag_p (tag_set)))
880 return list1 (tag_set); 888 return list1 (tag_set);
881 if (NILP (Fvalid_specifier_tag_set_p (tag_set))) 889 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
882 invalid_argument ("Invalid specifier tag-set", 890 invalid_argument ("Invalid specifier tag-set",
883 tag_set); 891 tag_set);
884 return tag_set; 892 return tag_set;
885 } 893 }
886 894
887 static Lisp_Object 895 static Lisp_Object
888 canonicalize_tag_set (Lisp_Object tag_set) 896 canonicalize_tag_set (Lisp_Object tag_set)
971 } 979 }
972 980
973 return 1; 981 return 1;
974 } 982 }
975 983
984 static int
985 charset_matches_specifier_tag_set_p (Lisp_Object charset,
986 Lisp_Object tag_set,
987 enum font_specifier_matchspec_stages
988 stage)
989 {
990 Lisp_Object rest;
991 int res = 0;
992
993 assert(stage != impossible);
994
995 LIST_LOOP (rest, tag_set)
996 {
997 Lisp_Object tag = XCAR (rest);
998 Lisp_Object assoc;
999
1000 /* This function will not ever be called with a charset for which the
1001 relevant information hasn't been calculated (the information is
1002 calculated with the creation of every charset). */
1003 assert (!NILP(XVECTOR_DATA
1004 (Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset)
1005 - MIN_LEADING_BYTE]));
1006
1007 /* Now, find out what the pre-calculated value is. */
1008 assoc = assq_no_quit(tag,
1009 XVECTOR_DATA(Vcharset_tag_lists)
1010 [XCHARSET_LEADING_BYTE(charset)
1011 - MIN_LEADING_BYTE]);
1012
1013 if (!(NILP(assoc)) && !(NILP(XCDR(assoc))))
1014 {
1015 assert(VECTORP(XCDR(assoc)));
1016
1017 /* In the event that a tag specifies a charset, then the specifier
1018 must match for (this stage and this charset) for all
1019 charset-specifying tags. */
1020 if (NILP(XVECTOR_DATA(XCDR(assoc))[stage]))
1021 {
1022 /* It doesn't match for this tag, even though the tag
1023 specifies a charset. Return 0. */
1024 return 0;
1025 }
1026
1027 /* This tag specifies charset limitations, and this charset and
1028 stage match those charset limitations.
1029
1030 In the event that a later tag specifies charset limitations
1031 that don't match, the return 0 above prevents us giving a
1032 positive match. */
1033 res = 1;
1034 }
1035 }
1036
1037 return res;
1038 }
1039
1040
976 DEFUN ("device-matches-specifier-tag-set-p", 1041 DEFUN ("device-matches-specifier-tag-set-p",
977 Fdevice_matches_specifier_tag_set_p, 2, 2, 0, /* 1042 Fdevice_matches_specifier_tag_set_p, 2, 2, 0, /*
978 Return non-nil if DEVICE matches specifier tag set TAG-SET. 1043 Return non-nil if DEVICE matches specifier tag set TAG-SET.
979 This means that DEVICE matches each tag in the tag set. (Every 1044 This means that DEVICE matches each tag in the tag set. (Every
980 tag recognized by XEmacs has a predicate associated with it that 1045 tag recognized by XEmacs has a predicate associated with it that
988 invalid_argument ("Invalid tag set", tag_set); 1053 invalid_argument ("Invalid tag set", tag_set);
989 1054
990 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil; 1055 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil;
991 } 1056 }
992 1057
993 DEFUN ("define-specifier-tag", Fdefine_specifier_tag, 1, 2, 0, /* 1058 Lisp_Object
1059 define_specifier_tag(Lisp_Object tag, Lisp_Object device_predicate,
1060 Lisp_Object charset_predicate)
1061 {
1062 Lisp_Object assoc = assq_no_quit (tag, Vuser_defined_tags),
1063 concons, devcons, charpres = Qnil;
1064 int recompute_devices = 0, recompute_charsets = 0, i, max_args = -1;
1065
1066 if (NILP (assoc))
1067 {
1068 recompute_devices = recompute_charsets = 1;
1069 Vuser_defined_tags = Fcons (list3 (tag, device_predicate,
1070 charset_predicate),
1071 Vuser_defined_tags);
1072 DEVICE_LOOP_NO_BREAK (devcons, concons)
1073 {
1074 struct device *d = XDEVICE (XCAR (devcons));
1075 /* Initially set the value to t in case of error
1076 in device_predicate */
1077 DEVICE_USER_DEFINED_TAGS (d) =
1078 Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d));
1079 }
1080
1081 if (!NILP (charset_predicate))
1082 {
1083 max_args = XINT(Ffunction_max_args(charset_predicate));
1084 if (max_args < 1)
1085 {
1086 invalid_argument
1087 ("Charset predicate must be able to take an argument", tag);
1088 }
1089 }
1090 }
1091 else if (!NILP (device_predicate) && !NILP (XCADR (assoc)))
1092 {
1093 recompute_devices = 1;
1094 XCDR (assoc) = list2(device_predicate, charset_predicate);
1095 }
1096 else if (!NILP (charset_predicate) || !NILP(XCADDR (assoc)))
1097 {
1098 max_args = XINT(Ffunction_max_args(charset_predicate));
1099 if (max_args < 1)
1100 {
1101 invalid_argument
1102 ("Charset predicate must be able to take an argument", tag);
1103 }
1104
1105 /* If there exists a charset_predicate for the tag currently (even if
1106 the new charset_predicate is nil), or if we're adding one, we need
1107 to recompute. This contrasts with the device predicates, where we
1108 don't need to recompute if the old and new device predicates are
1109 both nil. */
1110
1111 recompute_charsets = 1;
1112 XCDR (assoc) = list2(device_predicate, charset_predicate);
1113 }
1114
1115 /* Recompute the tag values for all devices and charsets, if necessary. In
1116 the special case where both the old and new device_predicates are nil,
1117 we know that we don't have to do it for the device. (It's probably
1118 common for people to call (define-specifier-tag) more than once on the
1119 same tag, and the most common case is where DEVICE_PREDICATE is not
1120 specified.) */
1121
1122 if (recompute_devices)
1123 {
1124 DEVICE_LOOP_NO_BREAK (devcons, concons)
1125 {
1126 Lisp_Object device = XCAR (devcons);
1127 assoc = assq_no_quit (tag,
1128 DEVICE_USER_DEFINED_TAGS (XDEVICE (device)));
1129 assert (CONSP (assoc));
1130 if (NILP (device_predicate))
1131 XCDR (assoc) = Qt;
1132 else
1133 XCDR (assoc) = !NILP (call1 (device_predicate, device)) ? Qt
1134 : Qnil;
1135 }
1136 }
1137
1138 if (recompute_charsets)
1139 {
1140 if (NILP(charset_predicate))
1141 {
1142 charpres = Qnil;
1143 }
1144
1145 for (i = 0; i < NUM_LEADING_BYTES; ++i)
1146 {
1147 if (NILP(charset_by_leading_byte(MIN_LEADING_BYTE + i)))
1148 {
1149 continue;
1150 }
1151
1152 assoc = assq_no_quit (tag,
1153 XVECTOR_DATA(Vcharset_tag_lists)[i]);
1154
1155 if (!NILP(charset_predicate))
1156 {
1157 static int line_1147_calls;
1158 ++line_1147_calls;
1159 charpres = make_vector(impossible, Qnil);
1160
1161 /* If you want to extend the number of stages available, here
1162 in setup_charset_initial_specifier_tags, and in specifier.h
1163 is where you want to go. */
1164
1165 #define DEFINE_SPECIFIER_TAG_FROB(stage) do { \
1166 if (max_args > 1) \
1167 { \
1168 XVECTOR_DATA(charpres)[stage] = \
1169 call2_trapping_problems \
1170 ("Error during specifier tag charset predicate," \
1171 " stage " #stage, charset_predicate, \
1172 charset_by_leading_byte(MIN_LEADING_BYTE + i), \
1173 Q##stage, 0); \
1174 } \
1175 else \
1176 { \
1177 XVECTOR_DATA(charpres)[stage] = \
1178 call1_trapping_problems \
1179 ("Error during specifier tag charset predicate," \
1180 " stage " #stage, charset_predicate, \
1181 charset_by_leading_byte(MIN_LEADING_BYTE + i), \
1182 0); \
1183 } \
1184 \
1185 if (UNBOUNDP(XVECTOR_DATA(charpres)[stage])) \
1186 { \
1187 XVECTOR_DATA(charpres)[stage] = Qnil; \
1188 } \
1189 else if (!NILP(XVECTOR_DATA(charpres)[stage])) \
1190 { \
1191 /* Don't want refs to random other objects. */ \
1192 XVECTOR_DATA(charpres)[stage] = Qt; \
1193 } \
1194 } while (0)
1195
1196 DEFINE_SPECIFIER_TAG_FROB (initial);
1197 DEFINE_SPECIFIER_TAG_FROB (final);
1198
1199 #undef DEFINE_SPECIFIER_TAG_FROB
1200
1201 }
1202
1203 if (!NILP(assoc))
1204 {
1205 assert(CONSP(assoc));
1206 XCDR (assoc) = charpres;
1207 }
1208 else
1209 {
1210 XVECTOR_DATA(Vcharset_tag_lists)[i]
1211 = Fcons(Fcons(tag, charpres),
1212 XVECTOR_DATA (Vcharset_tag_lists)[i]);
1213 }
1214 }
1215 }
1216 return Qt;
1217 }
1218
1219 DEFUN ("define-specifier-tag", Fdefine_specifier_tag, 1, 3, 0, /*
994 Define a new specifier tag. 1220 Define a new specifier tag.
995 If PREDICATE is specified, it should be a function of one argument 1221
996 \(a device) that specifies whether the tag matches that particular 1222 If DEVICE-PREDICATE is specified, it should be a function of one argument
997 device. If PREDICATE is omitted, the tag matches all devices. 1223 \(a device) that specifies whether the tag matches that particular device.
998 1224 If DEVICE-PREDICATE is omitted, the tag matches all devices.
999 You can redefine an existing user-defined specifier tag. However, 1225
1000 you cannot redefine the built-in specifier tags (the device types 1226 If CHARSET-PREDICATE is supplied, it should be a function taking a single
1001 and classes) or the symbols nil, t, `all', or `global'. 1227 Lisp character set argument. A tag's charset predicate is primarily used to
1002 */ 1228 determine what font to use for a given \(set of) charset\(s) when that tag
1003 (tag, predicate)) 1229 is used in a set-face-font call; a non-nil return value indicates that the
1004 { 1230 tag matches the charset.
1005 Lisp_Object assoc, devcons, concons; 1231
1006 int recompute = 0; 1232 The font matching process also has a concept of stages; the defined stages
1233 are currently `initial' and `final', and there exist specifier tags with
1234 those names that correspond to those stages. On X11, 'initial is used when
1235 the font matching process is looking for fonts that match the desired
1236 registries of the charset--see the `charset-registries' function. If that
1237 match process fails, then the 'final tag becomes relevant; this means that a
1238 more general lookup is desired, and that a font doesn't necessarily have to
1239 match the desired XLFD for the face, just the charset repertoire for this
1240 charset. It also means that the charset registry and encoding used will be
1241 `iso10646-1', and the characters will be converted to display using that
1242 registry.
1243
1244 If a tag set matches no character set; the two-stage match process will
1245 ignore the tag on its first pass, but if no match is found, it will respect
1246 it on the second pass, where character set information is ignored.
1247
1248 You can redefine an existing user-defined specifier tag. However, you
1249 cannot redefine most of the built-in specifier tags \(the device types and
1250 classes, `initial', and `final') or the symbols nil, t, `all', or `global'.
1251 Note that if a device type is not supported in this XEmacs, it will not be
1252 available as a built-in specifier tag; this is probably something we should
1253 change.
1254 */
1255 (tag, device_predicate, charset_predicate))
1256 {
1257 int max_args;
1007 1258
1008 CHECK_SYMBOL (tag); 1259 CHECK_SYMBOL (tag);
1009 if (valid_device_class_p (tag) || 1260 if (valid_device_class_p (tag) ||
1010 valid_console_type_p (tag)) 1261 valid_console_type_p (tag) ||
1262 EQ (tag, Qinitial) || EQ (tag, Qfinal))
1011 invalid_change ("Cannot redefine built-in specifier tags", tag); 1263 invalid_change ("Cannot redefine built-in specifier tags", tag);
1012 /* Try to prevent common instantiators and locales from being 1264 /* Try to prevent common instantiators and locales from being
1013 redefined, to reduce ambiguity */ 1265 redefined, to reduce ambiguity */
1014 if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal)) 1266 if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal))
1015 invalid_change ("Cannot define nil, t, `all', or `global'", tag); 1267 invalid_change ("Cannot define nil, t, `all', or `global'", tag);
1016 assoc = assq_no_quit (tag, Vuser_defined_tags); 1268
1017 if (NILP (assoc)) 1269 if (!NILP (charset_predicate))
1018 { 1270 {
1019 recompute = 1; 1271 max_args = XINT(Ffunction_max_args(charset_predicate));
1020 Vuser_defined_tags = Fcons (Fcons (tag, predicate), Vuser_defined_tags); 1272 if (max_args != 1)
1021 DEVICE_LOOP_NO_BREAK (devcons, concons) 1273 {
1022 { 1274 /* We only allow the stage argument to be specifed from C. */
1023 struct device *d = XDEVICE (XCAR (devcons)); 1275 invalid_change ("Charset predicate must take one argument",
1024 /* Initially set the value to t in case of error 1276 tag);
1025 in predicate */ 1277 }
1026 DEVICE_USER_DEFINED_TAGS (d) = 1278 }
1027 Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d)); 1279
1028 } 1280 return define_specifier_tag(tag, device_predicate, charset_predicate);
1029 }
1030 else if (!NILP (predicate) && !NILP (XCDR (assoc)))
1031 {
1032 recompute = 1;
1033 XCDR (assoc) = predicate;
1034 }
1035
1036 /* recompute the tag values for all devices. However, in the special
1037 case where both the old and new predicates are nil, we know that
1038 we don't have to do this. (It's probably common for people to
1039 call (define-specifier-tag) more than once on the same tag,
1040 and the most common case is where PREDICATE is not specified.) */
1041
1042 if (recompute)
1043 {
1044 DEVICE_LOOP_NO_BREAK (devcons, concons)
1045 {
1046 Lisp_Object device = XCAR (devcons);
1047 assoc = assq_no_quit (tag,
1048 DEVICE_USER_DEFINED_TAGS (XDEVICE (device)));
1049 assert (CONSP (assoc));
1050 if (NILP (predicate))
1051 XCDR (assoc) = Qt;
1052 else
1053 XCDR (assoc) = !NILP (call1 (predicate, device)) ? Qt : Qnil;
1054 }
1055 }
1056
1057 return Qnil;
1058 } 1281 }
1059 1282
1060 /* Called at device-creation time to initialize the user-defined 1283 /* Called at device-creation time to initialize the user-defined
1061 tag values for the newly-created device. */ 1284 tag values for the newly-created device. */
1062 1285
1063 void 1286 void
1064 setup_device_initial_specifier_tags (struct device *d) 1287 setup_device_initial_specifier_tags (struct device *d)
1065 { 1288 {
1066 Lisp_Object rest, rest2; 1289 Lisp_Object rest, rest2;
1067 Lisp_Object device = wrap_device (d); 1290 Lisp_Object device = wrap_device (d);
1291 Lisp_Object device_predicate, charset_predicate;
1292 int list_len;
1068 1293
1069 DEVICE_USER_DEFINED_TAGS (d) = Fcopy_alist (Vuser_defined_tags); 1294 DEVICE_USER_DEFINED_TAGS (d) = Fcopy_alist (Vuser_defined_tags);
1070 1295
1071 /* Now set up the initial values */ 1296 /* Now set up the initial values */
1072 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d)) 1297 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
1073 XCDR (XCAR (rest)) = Qt; 1298 XCDR (XCAR (rest)) = Qt;
1074 1299
1075 for (rest = Vuser_defined_tags, rest2 = DEVICE_USER_DEFINED_TAGS (d); 1300 for (rest = Vuser_defined_tags, rest2 = DEVICE_USER_DEFINED_TAGS (d);
1076 !NILP (rest); rest = XCDR (rest), rest2 = XCDR (rest2)) 1301 !NILP (rest); rest = XCDR (rest), rest2 = XCDR (rest2))
1077 { 1302 {
1078 Lisp_Object predicate = XCDR (XCAR (rest)); 1303 GET_LIST_LENGTH(XCAR(rest), list_len);
1079 if (NILP (predicate)) 1304
1080 XCDR (XCAR (rest2)) = Qt; 1305 assert(3 == list_len);
1306
1307 device_predicate = XCADR(XCAR (rest));
1308 charset_predicate = XCADDR(XCAR (rest));
1309
1310 if (NILP (device_predicate))
1311 {
1312 XCDR (XCAR (rest2)) = list2(Qt, charset_predicate);
1313 }
1081 else 1314 else
1082 XCDR (XCAR (rest2)) = 1315 {
1083 !NILP (call_critical_lisp_code (d, predicate, device)) ? Qt : Qnil; 1316 device_predicate = !NILP (call_critical_lisp_code
1084 } 1317 (d, device_predicate, device))
1085 } 1318 ? Qt : Qnil;
1319 XCDR (XCAR (rest2)) = list2(device_predicate, charset_predicate);
1320 }
1321 }
1322 }
1323
1324 void
1325 setup_charset_initial_specifier_tags (Lisp_Object charset)
1326 {
1327 Lisp_Object rest, charset_predicate, tag, new_value;
1328 Lisp_Object charset_tag_list = Qnil;
1329
1330 LIST_LOOP (rest, Vuser_defined_tags)
1331 {
1332 tag = XCAR(XCAR(rest));
1333 charset_predicate = XCADDR(XCAR (rest));
1334
1335 if (NILP(charset_predicate))
1336 {
1337 continue;
1338 }
1339
1340 new_value = make_vector(impossible, Qnil);
1341
1342 #define SETUP_CHARSET_TAGS_FROB(stage) do { \
1343 \
1344 XVECTOR_DATA(new_value)[stage] = call2_trapping_problems \
1345 ("Error during specifier tag charset predicate," \
1346 " stage " #stage, \
1347 charset_predicate, charset, Q##stage, 0); \
1348 \
1349 if (UNBOUNDP(XVECTOR_DATA(new_value)[stage])) \
1350 { \
1351 XVECTOR_DATA(new_value)[stage] = Qnil; \
1352 } \
1353 else if (!NILP(XVECTOR_DATA(new_value)[stage])) \
1354 { \
1355 /* Don't want random other objects hanging around. */ \
1356 XVECTOR_DATA(new_value)[stage] = Qt; \
1357 } \
1358 \
1359 } while (0)
1360
1361 SETUP_CHARSET_TAGS_FROB (initial);
1362 SETUP_CHARSET_TAGS_FROB (final);
1363 /* More later? */
1364
1365 #undef SETUP_CHARSET_TAGS_FROB
1366
1367 charset_tag_list = Fcons(Fcons(tag, new_value), charset_tag_list);
1368 }
1369
1370 XVECTOR_DATA
1371 (Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset) - MIN_LEADING_BYTE]
1372 = charset_tag_list;
1373 }
1374
1375 #ifdef DEBUG_XEMACS
1376
1377 /* Nothing's calling this, I see no reason to keep it in the production
1378 builds. */
1086 1379
1087 DEFUN ("device-matching-specifier-tag-list", 1380 DEFUN ("device-matching-specifier-tag-list",
1088 Fdevice_matching_specifier_tag_list, 1381 Fdevice_matching_specifier_tag_list,
1089 0, 1, 0, /* 1382 0, 1, 0, /*
1090 Return a list of all specifier tags matching DEVICE. 1383 Return a list of all specifier tags matching DEVICE.
1091 DEVICE defaults to the selected device if omitted. 1384 DEVICE defaults to the selected device if omitted.
1092 */ 1385 */
1093 (device)) 1386 (device))
1094 { 1387 {
1095 struct device *d = decode_device (device); 1388 struct device *d = decode_device (device);
1096 Lisp_Object rest, list = Qnil; 1389 Lisp_Object rest, list = Qnil;
1097 struct gcpro gcpro1; 1390 struct gcpro gcpro1;
1098 1391
1099 GCPRO1 (list); 1392 GCPRO1 (list);
1100 1393
1101 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d)) 1394 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
1102 { 1395 {
1103 if (!NILP (XCDR (XCAR (rest)))) 1396 if (!NILP (XCADR (XCAR (rest))))
1104 list = Fcons (XCAR (XCAR (rest)), list); 1397 list = Fcons (XCAR (XCAR (rest)), list);
1105 } 1398 }
1106 1399
1107 list = Fnreverse (list); 1400 list = Fnreverse (list);
1108 list = Fcons (DEVICE_CLASS (d), list); 1401 list = Fcons (DEVICE_CLASS (d), list);
1109 list = Fcons (DEVICE_TYPE (d), list); 1402 list = Fcons (DEVICE_TYPE (d), list);
1110 1403
1111 RETURN_UNGCPRO (list); 1404 RETURN_UNGCPRO (list);
1112 } 1405 }
1113 1406
1407 #endif /* DEBUG_XEMACS */
1408
1114 DEFUN ("specifier-tag-list", Fspecifier_tag_list, 0, 0, 0, /* 1409 DEFUN ("specifier-tag-list", Fspecifier_tag_list, 0, 0, 0, /*
1115 Return a list of all currently-defined specifier tags. 1410 Return a list of all currently-defined specifier tags.
1116 This includes the built-in ones (the device types and classes). 1411 This includes the built-in ones (the device types and classes).
1117 */ 1412 */
1118 ()) 1413 ())
1130 list = nconc2 (Fcopy_sequence (Vconsole_type_list), list); 1425 list = nconc2 (Fcopy_sequence (Vconsole_type_list), list);
1131 1426
1132 RETURN_UNGCPRO (list); 1427 RETURN_UNGCPRO (list);
1133 } 1428 }
1134 1429
1135 DEFUN ("specifier-tag-predicate", Fspecifier_tag_predicate, 1, 1, 0, /* 1430 DEFUN ("specifier-tag-device-predicate", Fspecifier_tag_device_predicate,
1136 Return the predicate for the given specifier tag. 1431 1, 1, 0, /*
1432 Return the device predicate for the given specifier tag.
1137 */ 1433 */
1138 (tag)) 1434 (tag))
1139 { 1435 {
1140 /* The return value of this function must be GCPRO'd. */ 1436 /* The return value of this function must be GCPRO'd. */
1141 CHECK_SYMBOL (tag); 1437 CHECK_SYMBOL (tag);
1142 1438
1143 if (NILP (Fvalid_specifier_tag_p (tag))) 1439 if (NILP (Fvalid_specifier_tag_p (tag)))
1144 invalid_argument ("Invalid specifier tag", 1440 invalid_argument ("Invalid specifier tag",
1145 tag); 1441 tag);
1146 1442
1147 /* Make up some predicates for the built-in types */ 1443 /* Make up some predicates for the built-in types */
1148 1444
1149 if (valid_console_type_p (tag)) 1445 if (valid_console_type_p (tag))
1150 return list3 (Qlambda, list1 (Qdevice), 1446 return list3 (Qlambda, list1 (Qdevice),
1154 if (valid_device_class_p (tag)) 1450 if (valid_device_class_p (tag))
1155 return list3 (Qlambda, list1 (Qdevice), 1451 return list3 (Qlambda, list1 (Qdevice),
1156 list3 (Qeq, list2 (Qquote, tag), 1452 list3 (Qeq, list2 (Qquote, tag),
1157 list2 (Qdevice_class, Qdevice))); 1453 list2 (Qdevice_class, Qdevice)));
1158 1454
1159 return XCDR (assq_no_quit (tag, Vuser_defined_tags)); 1455 return XCADR (assq_no_quit (tag, Vuser_defined_tags));
1456 }
1457
1458 DEFUN ("specifier-tag-charset-predicate", Fspecifier_tag_charset_predicate,
1459 1, 1, 0, /*
1460 Return the charset predicate for the given specifier tag.
1461 */
1462 (tag))
1463 {
1464 /* The return value of this function must be GCPRO'd. */
1465 CHECK_SYMBOL (tag);
1466
1467 if (NILP (Fvalid_specifier_tag_p (tag)))
1468 invalid_argument ("Invalid specifier tag",
1469 tag);
1470
1471 return XCADDR (assq_no_quit (tag, Vuser_defined_tags));
1160 } 1472 }
1161 1473
1162 /* Return true if A "matches" B. If EXACT_P is 0, A must be a subset of B. 1474 /* Return true if A "matches" B. If EXACT_P is 0, A must be a subset of B.
1163 Otherwise, A must be `equal' to B. The sets must be canonicalized. */ 1475 Otherwise, A must be `equal' to B. The sets must be canonicalized. */
1164 static int 1476 static int
1165 tag_sets_match_p (Lisp_Object a, Lisp_Object b, int exact_p) 1477 tag_sets_match_p (Lisp_Object a, Lisp_Object b, int exact_p)
1166 { 1478 {
1167 if (!exact_p) 1479 if (!exact_p)
1168 { 1480 {
1266 Lisp_Object tag_set; 1578 Lisp_Object tag_set;
1267 1579
1268 if (!CONSP (inst_pair)) 1580 if (!CONSP (inst_pair))
1269 { 1581 {
1270 maybe_sferror ( 1582 maybe_sferror (
1271 "Invalid instantiator pair", inst_pair, 1583 "Invalid instantiator pair", inst_pair,
1272 Qspecifier, errb); 1584 Qspecifier, errb);
1273 return Qnil; 1585 return Qnil;
1274 } 1586 }
1275 if (NILP (Fvalid_specifier_tag_set_p (tag_set = XCAR (inst_pair)))) 1587 if (NILP (Fvalid_specifier_tag_set_p (tag_set = XCAR (inst_pair))))
1276 { 1588 {
1277 maybe_invalid_argument ( 1589 maybe_invalid_argument (
1278 "Invalid specifier tag", tag_set, 1590 "Invalid specifier tag", tag_set,
1279 Qspecifier, errb); 1591 Qspecifier, errb);
1280 return Qnil; 1592 return Qnil;
1281 } 1593 }
1282 1594
1283 if (NILP (check_valid_instantiator (XCDR (inst_pair), meths, errb))) 1595 if (NILP (check_valid_instantiator (XCDR (inst_pair), meths, errb)))
1284 return Qnil; 1596 return Qnil;
1315 { 1627 {
1316 Lisp_Object locale; 1628 Lisp_Object locale;
1317 if (!CONSP (spec)) 1629 if (!CONSP (spec))
1318 { 1630 {
1319 maybe_sferror ( 1631 maybe_sferror (
1320 "Invalid specification list", spec_list, 1632 "Invalid specification list", spec_list,
1321 Qspecifier, errb); 1633 Qspecifier, errb);
1322 return Qnil; 1634 return Qnil;
1323 } 1635 }
1324 if (NILP (Fvalid_specifier_locale_p (locale = XCAR (spec)))) 1636 if (NILP (Fvalid_specifier_locale_p (locale = XCAR (spec))))
1325 { 1637 {
1326 maybe_invalid_argument ( 1638 maybe_invalid_argument (
1327 "Invalid specifier locale", locale, 1639 "Invalid specifier locale", locale,
1328 Qspecifier, errb); 1640 Qspecifier, errb);
1329 return Qnil; 1641 return Qnil;
1330 } 1642 }
1331 1643
1332 if (NILP (check_valid_inst_list (XCDR (spec), meths, errb))) 1644 if (NILP (check_valid_inst_list (XCDR (spec), meths, errb)))
1333 return Qnil; 1645 return Qnil;
1412 /* This gets hit so much that the function call overhead had a 1724 /* This gets hit so much that the function call overhead had a
1413 measurable impact (according to Quantify). #### We should figure 1725 measurable impact (according to Quantify). #### We should figure
1414 out the frequency with which this is called with the various types 1726 out the frequency with which this is called with the various types
1415 and reorder the check accordingly. */ 1727 and reorder the check accordingly. */
1416 #define SPECIFIER_GET_SPEC_LIST(specifier, type) \ 1728 #define SPECIFIER_GET_SPEC_LIST(specifier, type) \
1417 (type == LOCALE_GLOBAL ? &(XSPECIFIER (specifier)->global_specs) : \ 1729 (type == LOCALE_GLOBAL ? &(XSPECIFIER (specifier)->global_specs) : \
1418 type == LOCALE_DEVICE ? &(XSPECIFIER (specifier)->device_specs) : \ 1730 type == LOCALE_DEVICE ? &(XSPECIFIER (specifier)->device_specs) : \
1419 type == LOCALE_FRAME ? &(XSPECIFIER (specifier)->frame_specs) : \ 1731 type == LOCALE_FRAME ? &(XSPECIFIER (specifier)->frame_specs) : \
1420 type == LOCALE_WINDOW ? &(XWEAK_LIST_LIST \ 1732 type == LOCALE_WINDOW ? &(XWEAK_LIST_LIST \
1421 (XSPECIFIER (specifier)->window_specs)) : \ 1733 (XSPECIFIER (specifier)->window_specs)) : \
1422 type == LOCALE_BUFFER ? &(XSPECIFIER (specifier)->buffer_specs) : \ 1734 type == LOCALE_BUFFER ? &(XSPECIFIER (specifier)->buffer_specs) : \
1423 0) 1735 0)
1424 1736
1425 static Lisp_Object * 1737 static Lisp_Object *
1426 specifier_get_inst_list (Lisp_Object specifier, Lisp_Object locale, 1738 specifier_get_inst_list (Lisp_Object specifier, Lisp_Object locale,
1427 enum spec_locale_type type) 1739 enum spec_locale_type type)
1428 { 1740 {
1757 specifier, and is an enum that corresponds to the values in 2069 specifier, and is an enum that corresponds to the values in
1758 `add-spec-to-specifier'. The calling routine is responsible for 2070 `add-spec-to-specifier'. The calling routine is responsible for
1759 validating LOCALE and INST-LIST, but the tag-sets in INST-LIST 2071 validating LOCALE and INST-LIST, but the tag-sets in INST-LIST
1760 do not need to be canonicalized. */ 2072 do not need to be canonicalized. */
1761 2073
1762 /* #### I really need to rethink the after-change 2074 /* #### I really need to rethink the after-change
1763 functions to make them easier to use and more efficient. */ 2075 functions to make them easier to use and more efficient. */
1764 2076
1765 static void 2077 static void
1766 specifier_add_spec (Lisp_Object specifier, Lisp_Object locale, 2078 specifier_add_spec (Lisp_Object specifier, Lisp_Object locale,
1767 Lisp_Object inst_list, enum spec_add_meth add_meth) 2079 Lisp_Object inst_list, enum spec_add_meth add_meth)
1768 { 2080 {
1854 } 2166 }
1855 2167
1856 /* map MAPFUN over the locales in SPECIFIER that are given in LOCALE. 2168 /* map MAPFUN over the locales in SPECIFIER that are given in LOCALE.
1857 CLOSURE is passed unchanged to MAPFUN. LOCALE can be one of 2169 CLOSURE is passed unchanged to MAPFUN. LOCALE can be one of
1858 2170
1859 -- nil (same as `all') 2171 -- nil (same as `all')
1860 -- a single locale, locale type, or `all' 2172 -- a single locale, locale type, or `all'
1861 -- a list of locales, locale types, and/or `all' 2173 -- a list of locales, locale types, and/or `all'
1862 2174
1863 MAPFUN is called for each locale and locale type given; for `all', 2175 MAPFUN is called for each locale and locale type given; for `all',
1864 it is called for the locale `global' and for the four possible 2176 it is called for the locale `global' and for the four possible
1865 locale types. In each invocation, either LOCALE will be a locale 2177 locale types. In each invocation, either LOCALE will be a locale
1866 and LOCALE_TYPE will be the locale type of this locale, 2178 and LOCALE_TYPE will be the locale type of this locale,
1867 or LOCALE will be nil and LOCALE_TYPE will be a locale type. 2179 or LOCALE will be nil and LOCALE_TYPE will be a locale type.
1868 If MAPFUN ever returns non-zero, the mapping is halted and the 2180 If MAPFUN ever returns non-zero, the mapping is halted and the
1869 value returned is returned from map_specifier(). Otherwise, the 2181 value returned is returned from map_specifier(). Otherwise, the
1870 mapping proceeds to the end and map_specifier() returns 0. 2182 mapping proceeds to the end and map_specifier() returns 0.
1871 */ 2183 */
1872 2184
1873 static int 2185 static int
1874 map_specifier (Lisp_Object specifier, Lisp_Object locale, 2186 map_specifier (Lisp_Object specifier, Lisp_Object locale,
1875 int (*mapfun) (Lisp_Object specifier, 2187 int (*mapfun) (Lisp_Object specifier,
1876 Lisp_Object locale, 2188 Lisp_Object locale,
2146 \(The default value of nil is a subset of all tag sets, so in this case 2458 \(The default value of nil is a subset of all tag sets, so in this case
2147 no instantiators will be screened out.) If EXACT-P is non-nil, however, 2459 no instantiators will be screened out.) If EXACT-P is non-nil, however,
2148 TAG-SET must be equal to an instantiator's tag set for the instantiator 2460 TAG-SET must be equal to an instantiator's tag set for the instantiator
2149 to be returned. 2461 to be returned.
2150 */ 2462 */
2151 (specifier, locale, tag_set, exact_p)) 2463 (specifier, locale, tag_set, exact_p))
2152 { 2464 {
2153 struct specifier_spec_list_closure cl; 2465 struct specifier_spec_list_closure cl;
2154 struct gcpro gcpro1, gcpro2; 2466 struct gcpro gcpro1, gcpro2;
2155 2467
2156 CHECK_SPECIFIER (specifier); 2468 CHECK_SPECIFIER (specifier);
2345 else 2657 else
2346 { 2658 {
2347 CHECK_SPECIFIER (dest); 2659 CHECK_SPECIFIER (dest);
2348 check_modifiable_specifier (dest); 2660 check_modifiable_specifier (dest);
2349 if (XSPECIFIER (dest)->methods != XSPECIFIER (specifier)->methods) 2661 if (XSPECIFIER (dest)->methods != XSPECIFIER (specifier)->methods)
2350 invalid_argument ("Specifiers not of same type", Qunbound); 2662 invalid_argument ("Specifiers not of same type", Qunbound);
2351 } 2663 }
2352 2664
2353 cl.dest = dest; 2665 cl.dest = dest;
2354 GCPRO1 (dest); 2666 GCPRO1 (dest);
2355 map_specifier (specifier, locale, copy_specifier_mapfun, 2667 map_specifier (specifier, locale, copy_specifier_mapfun,
2494 Lisp_Object depth, 2806 Lisp_Object depth,
2495 Lisp_Object *instantiator) 2807 Lisp_Object *instantiator)
2496 { 2808 {
2497 /* This function can GC */ 2809 /* This function can GC */
2498 Lisp_Specifier *sp; 2810 Lisp_Specifier *sp;
2499 Lisp_Object device; 2811 Lisp_Object device, charset = Qnil, rest;
2500 Lisp_Object rest; 2812 int count = specpdl_depth (), respected_charsets = 0;
2501 int count = specpdl_depth ();
2502 struct gcpro gcpro1, gcpro2; 2813 struct gcpro gcpro1, gcpro2;
2814 enum font_specifier_matchspec_stages stage = initial;
2815 #ifdef DEBUG_XEMACS
2816 int non_ascii;
2817 #endif
2503 2818
2504 GCPRO2 (specifier, inst_list); 2819 GCPRO2 (specifier, inst_list);
2505 2820
2506 sp = XSPECIFIER (specifier); 2821 sp = XSPECIFIER (specifier);
2507 device = DOMAIN_DEVICE (domain); 2822 device = DOMAIN_DEVICE (domain);
2508 2823
2509 if (no_quit) 2824 if (no_quit)
2510 /* The instantiate method is allowed to call eval. Since it 2825 /* The instantiate method is allowed to call eval. Since it
2511 is quite common for this function to get called from somewhere in 2826 is quite common for this function to get called from somewhere in
2512 redisplay we need to make sure that quits are ignored. Otherwise 2827 redisplay we need to make sure that quits are ignored. Otherwise
2513 Fsignal will abort. */ 2828 Fsignal will abort. */
2514 specbind (Qinhibit_quit, Qt); 2829 specbind (Qinhibit_quit, Qt);
2515 2830
2516 LIST_LOOP (rest, inst_list) 2831 #ifdef MULE
2832 if (CONSP(matchspec) && (CHARSETP(XCAR(matchspec))))
2833 {
2834 charset = Ffind_charset(XCAR(matchspec));
2835
2836 #ifdef DEBUG_XEMACS
2837 /* This is mostly to have somewhere to set debug breakpoints. */
2838 if (!EQ(charset, Vcharset_ascii))
2839 {
2840 non_ascii = 1;
2841 }
2842 #endif /* DEBUG_XEMACS */
2843
2844 if (!NILP(XCDR(matchspec)))
2845 {
2846
2847 #define FROB(new_stage) if (EQ(Q##new_stage, XCDR(matchspec))) \
2848 { \
2849 stage = new_stage; \
2850 }
2851
2852 FROB(initial)
2853 else FROB(final)
2854 else assert(0);
2855 #undef FROB
2856
2857 }
2858 }
2859 #endif /* MULE */
2860
2861 LIST_LOOP(rest, inst_list)
2517 { 2862 {
2518 Lisp_Object tagged_inst = XCAR (rest); 2863 Lisp_Object tagged_inst = XCAR (rest);
2519 Lisp_Object tag_set = XCAR (tagged_inst); 2864 Lisp_Object tag_set = XCAR (tagged_inst);
2520 2865 Lisp_Object val, the_instantiator;
2521 if (device_matches_specifier_tag_set_p (device, tag_set)) 2866
2522 { 2867 if (!device_matches_specifier_tag_set_p (device, tag_set))
2523 Lisp_Object val = XCDR (tagged_inst); 2868 {
2524 Lisp_Object the_instantiator = val; 2869 continue;
2525 2870 }
2526 2871
2527 if (HAS_SPECMETH_P (sp, instantiate)) 2872 val = XCDR (tagged_inst);
2528 val = call_with_suspended_errors 2873 the_instantiator = val;
2529 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), 2874
2530 Qunbound, Qspecifier, errb, 5, specifier, 2875 if (!NILP(charset) &&
2531 matchspec, domain, val, depth); 2876 !(charset_matches_specifier_tag_set_p (charset, tag_set, stage)))
2532 2877 {
2533 if (!UNBOUNDP (val)) 2878 ++respected_charsets;
2534 { 2879 continue;
2535 unbind_to (count); 2880 }
2536 UNGCPRO; 2881
2537 if (instantiator) 2882 if (HAS_SPECMETH_P (sp, instantiate))
2538 *instantiator = the_instantiator; 2883 val = call_with_suspended_errors
2539 return val; 2884 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate),
2540 } 2885 Qunbound, Qspecifier, errb, 5, specifier,
2886 matchspec, domain, val, depth);
2887
2888 if (!UNBOUNDP (val))
2889 {
2890 unbind_to (count);
2891 UNGCPRO;
2892 if (instantiator)
2893 *instantiator = the_instantiator;
2894 return val;
2895 }
2896 }
2897
2898 /* We've checked all the tag sets, and checking the charset part of the
2899 specifier never returned 0 (preventing the attempted instantiation), so
2900 there's no need to loop for the second time to avoid checking the
2901 charsets. */
2902 if (!respected_charsets)
2903 {
2904 unbind_to (count);
2905 UNGCPRO;
2906 return Qunbound;
2907 }
2908
2909 /* Right, didn't instantiate a specifier last time, perhaps because we
2910 paid attention to the charset-specific aspects of the specifier. Try
2911 again without checking the charset information.
2912
2913 We can't emulate the approach for devices, defaulting to matching all
2914 character sets for a given specifier, because $random font instantiator
2915 cannot usefully show all character sets, and indeed having it try is a
2916 failure on our part. */
2917 LIST_LOOP (rest, inst_list)
2918 {
2919 Lisp_Object tagged_inst = XCAR (rest);
2920 Lisp_Object tag_set = XCAR (tagged_inst);
2921 Lisp_Object val, the_instantiator;
2922
2923 if (!device_matches_specifier_tag_set_p (device, tag_set))
2924 {
2925 continue;
2926 }
2927
2928 val = XCDR (tagged_inst);
2929 the_instantiator = val;
2930
2931 if (HAS_SPECMETH_P (sp, instantiate))
2932 val = call_with_suspended_errors
2933 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate),
2934 Qunbound, Qspecifier, errb, 5, specifier,
2935 matchspec, domain, val, depth);
2936
2937 if (!UNBOUNDP (val))
2938 {
2939 unbind_to (count);
2940 UNGCPRO;
2941 if (instantiator)
2942 *instantiator = the_instantiator;
2943 return val;
2541 } 2944 }
2542 } 2945 }
2543 2946
2544 unbind_to (count); 2947 unbind_to (count);
2545 UNGCPRO; 2948 UNGCPRO;
2550 specifier. Try to find one by checking the specifier types from most 2953 specifier. Try to find one by checking the specifier types from most
2551 specific (buffer) to most general (global). If we find an instance, 2954 specific (buffer) to most general (global). If we find an instance,
2552 return it. Otherwise return Qunbound. */ 2955 return it. Otherwise return Qunbound. */
2553 2956
2554 #define CHECK_INSTANCE_ENTRY(key, matchspec, type) do { \ 2957 #define CHECK_INSTANCE_ENTRY(key, matchspec, type) do { \
2555 Lisp_Object *CIE_inst_list = \ 2958 Lisp_Object *CIE_inst_list = \
2556 specifier_get_inst_list (specifier, key, type); \ 2959 specifier_get_inst_list (specifier, key, type); \
2557 if (CIE_inst_list) \ 2960 if (CIE_inst_list) \
2558 { \ 2961 { \
2559 Lisp_Object CIE_val = \ 2962 Lisp_Object CIE_val = \
2560 specifier_instance_from_inst_list (specifier, matchspec, \ 2963 specifier_instance_from_inst_list (specifier, matchspec, \
2561 domain, *CIE_inst_list, \ 2964 domain, *CIE_inst_list, \
2562 errb, no_quit, depth, \ 2965 errb, no_quit, depth, \
2563 instantiator); \ 2966 instantiator); \
2564 if (!UNBOUNDP (CIE_val)) \ 2967 if (!UNBOUNDP (CIE_val)) \
2565 return CIE_val; \ 2968 return CIE_val; \
2566 } \ 2969 } \
2567 } while (0) 2970 } while (0)
2568 2971
2569 /* We accept any window, frame or device domain and do our checking 2972 /* We accept any window, frame or device domain and do our checking
2570 starting from as specific a locale type as we can determine from the 2973 starting from as specific a locale type as we can determine from the
2571 domain we are passed and going on up through as many other locale types 2974 domain we are passed and going on up through as many other locale types
2572 as we can determine. In practice, when called from redisplay the 2975 as we can determine. In practice, when called from redisplay the
2917 return specifier_matching_foo_from_inst_list (specifier, Qunbound, 3320 return specifier_matching_foo_from_inst_list (specifier, Qunbound,
2918 domain, inst_list, default_, 3321 domain, inst_list, default_,
2919 0); 3322 0);
2920 } 3323 }
2921 3324
2922 DEFUN ("specifier-instantiator-from-inst-list", Fspecifier_instantiator_from_inst_list, 3325 DEFUN ("specifier-instantiator-from-inst-list",
2923 3, 4, 0, /* 3326 Fspecifier_instantiator_from_inst_list, 3, 4, 0, /*
2924 Attempt to convert an inst-list into an instance; return instantiator. 3327 Attempt to convert an inst-list into an instance; return instantiator.
2925 This is identical to `specifier-instance-from-inst-list' but returns 3328 This is identical to `specifier-instance-from-inst-list' but returns
2926 the instantiator used to generate the instance, rather than the instance 3329 the instantiator used to generate the instance, rather than the instance
2927 itself. 3330 itself.
2928 */ 3331 */
2986 You nearly always need to do something, e.g. set a dirty flag.) 3389 You nearly always need to do something, e.g. set a dirty flag.)
2987 3390
2988 If you create a built-in specifier, you should do the following: 3391 If you create a built-in specifier, you should do the following:
2989 3392
2990 - Make sure the file you create the specifier in has a 3393 - Make sure the file you create the specifier in has a
2991 specifier_vars_of_foo() function. If not, create it, declare it in 3394 specifier_vars_of_foo() function. If not, create it, declare it in
2992 symsinit.h, and make sure it's called in the appropriate place in 3395 symsinit.h, and make sure it's called in the appropriate place in
2993 emacs.c. 3396 emacs.c.
2994 - In specifier_vars_of_foo(), do a DEFVAR_SPECIFIER(), followed by 3397 - In specifier_vars_of_foo(), do a DEFVAR_SPECIFIER(), followed by
2995 initializing the specifier using Fmake_specifier(), followed by 3398 initializing the specifier using Fmake_specifier(), followed by
2996 set_specifier_fallback(), followed (optionally) by 3399 set_specifier_fallback(), followed (optionally) by
2997 set_specifier_caching(). 3400 set_specifier_caching().
2998 - If you used set_specifier_caching(), make sure to create the 3401 - If you used set_specifier_caching(), make sure to create the
2999 appropriate value-changed functions. Also make sure to add the 3402 appropriate value-changed functions. Also make sure to add the
3000 appropriate slots where the values are cached to frameslots.h and 3403 appropriate slots where the values are cached to frameslots.h and
3001 winslots.h. 3404 winslots.h.
3002 3405
3003 Do a grep for menubar_visible_p for an example. 3406 Do a grep for menubar_visible_p for an example.
3004 */ 3407 */
3005 3408
3006 /* #### It would be nice if the specifier caching automatically knew 3409 /* #### It would be nice if the specifier caching automatically knew
3023 if (!sp->caching) 3426 if (!sp->caching)
3024 #ifdef NEW_GC 3427 #ifdef NEW_GC
3025 sp->caching = alloc_lrecord_type (struct specifier_caching, 3428 sp->caching = alloc_lrecord_type (struct specifier_caching,
3026 &lrecord_specifier_caching); 3429 &lrecord_specifier_caching);
3027 #else /* not NEW_GC */ 3430 #else /* not NEW_GC */
3028 sp->caching = xnew_and_zero (struct specifier_caching); 3431 sp->caching = xnew_and_zero (struct specifier_caching);
3029 #endif /* not NEW_GC */ 3432 #endif /* not NEW_GC */
3030 sp->caching->offset_into_struct_window = struct_window_offset; 3433 sp->caching->offset_into_struct_window = struct_window_offset;
3031 sp->caching->value_changed_in_window = value_changed_in_window; 3434 sp->caching->value_changed_in_window = value_changed_in_window;
3032 sp->caching->offset_into_struct_frame = struct_frame_offset; 3435 sp->caching->offset_into_struct_frame = struct_frame_offset;
3033 sp->caching->value_changed_in_frame = value_changed_in_frame; 3436 sp->caching->value_changed_in_frame = value_changed_in_frame;
3324 /* Display table specifier type */ 3727 /* Display table specifier type */
3325 /************************************************************************/ 3728 /************************************************************************/
3326 3729
3327 DEFINE_SPECIFIER_TYPE (display_table); 3730 DEFINE_SPECIFIER_TYPE (display_table);
3328 3731
3329 #define VALID_SINGLE_DISPTABLE_INSTANTIATOR_P(instantiator) \ 3732 #define VALID_SINGLE_DISPTABLE_INSTANTIATOR_P(instantiator) \
3330 (VECTORP (instantiator) \ 3733 (VECTORP (instantiator) \
3331 || (CHAR_TABLEP (instantiator) \ 3734 || (CHAR_TABLEP (instantiator) \
3332 && (XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_CHAR \ 3735 && (XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_CHAR \
3333 || XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_GENERIC)) \ 3736 || XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_GENERIC)) \
3334 || RANGE_TABLEP (instantiator)) 3737 || RANGE_TABLEP (instantiator))
3335 3738
3336 static void 3739 static void
3337 display_table_validate (Lisp_Object instantiator) 3740 display_table_validate (Lisp_Object instantiator)
3352 if (!VALID_SINGLE_DISPTABLE_INSTANTIATOR_P (instantiator)) 3755 if (!VALID_SINGLE_DISPTABLE_INSTANTIATOR_P (instantiator))
3353 { 3756 {
3354 lose: 3757 lose:
3355 dead_wrong_type_argument 3758 dead_wrong_type_argument
3356 (display_table_specifier_methods->predicate_symbol, 3759 (display_table_specifier_methods->predicate_symbol,
3357 instantiator); 3760 instantiator);
3358 } 3761 }
3359 } 3762 }
3360 } 3763 }
3361 3764
3362 DEFUN ("display-table-specifier-p", Fdisplay_table_specifier_p, 1, 1, 0, /* 3765 DEFUN ("display-table-specifier-p", Fdisplay_table_specifier_p, 1, 1, 0, /*
3406 DEFSUBR (Fcanonicalize_tag_set); 3809 DEFSUBR (Fcanonicalize_tag_set);
3407 DEFSUBR (Fdevice_matches_specifier_tag_set_p); 3810 DEFSUBR (Fdevice_matches_specifier_tag_set_p);
3408 DEFSUBR (Fdefine_specifier_tag); 3811 DEFSUBR (Fdefine_specifier_tag);
3409 DEFSUBR (Fdevice_matching_specifier_tag_list); 3812 DEFSUBR (Fdevice_matching_specifier_tag_list);
3410 DEFSUBR (Fspecifier_tag_list); 3813 DEFSUBR (Fspecifier_tag_list);
3411 DEFSUBR (Fspecifier_tag_predicate); 3814 DEFSUBR (Fspecifier_tag_device_predicate);
3815 DEFSUBR (Fspecifier_tag_charset_predicate);
3412 3816
3413 DEFSUBR (Fcheck_valid_instantiator); 3817 DEFSUBR (Fcheck_valid_instantiator);
3414 DEFSUBR (Fvalid_instantiator_p); 3818 DEFSUBR (Fvalid_instantiator_p);
3415 DEFSUBR (Fcheck_valid_inst_list); 3819 DEFSUBR (Fcheck_valid_inst_list);
3416 DEFSUBR (Fvalid_inst_list_p); 3820 DEFSUBR (Fvalid_inst_list_p);
3507 Vuser_defined_tags = Qnil; 3911 Vuser_defined_tags = Qnil;
3508 staticpro (&Vuser_defined_tags); 3912 staticpro (&Vuser_defined_tags);
3509 3913
3510 Vunlock_ghost_specifiers = Qnil; 3914 Vunlock_ghost_specifiers = Qnil;
3511 staticpro (&Vunlock_ghost_specifiers); 3915 staticpro (&Vunlock_ghost_specifiers);
3512 } 3916
3917 Vcharset_tag_lists = make_vector(NUM_LEADING_BYTES, Qnil);
3918 staticpro (&Vcharset_tag_lists);
3919 }