Mercurial > hg > xemacs-beta
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 } |