Mercurial > hg > xemacs-beta
diff src/specifier.h @ 276:6330739388db r21-0b36
Import from CVS: tag r21-0b36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:30:37 +0200 |
parents | c5d627a313b1 |
children | 7df0dd720c89 |
line wrap: on
line diff
--- a/src/specifier.h Mon Aug 13 10:29:43 2007 +0200 +++ b/src/specifier.h Mon Aug 13 10:30:37 2007 +0200 @@ -24,6 +24,66 @@ #ifndef _XEMACS_SPECIFIER_H_ #define _XEMACS_SPECIFIER_H_ +/* + MAGIC SPECIFIERS + ================ + + Magic specifiers are used to provide fallback values for window + system provided specifications, reflecting user preferences on the + window system, such as default fonts, colors, scrollbar thickness + etc. + + A magic specifier consists of two specifier objects. The first one + behaves like a normal specifier in all sences. The second one, a + ghost specifier, is a fallback value for the first one. + + Ghost specifiers have the following properties: + - Have back pointers to their parent specifiers. + - Do not have instance data. Instead, they share parent's instance + data. + - Have the same methods structure pointer. + - Share parent's caching scheme. + - Store fallback value instead of their parent. + + Ghost specifiers normally are not modifiable at the lisp level, and + only used to supply fallback instance values. Although, under + certain rare conditions, all functions that modify specifiers + operate on ghost objects. This behavior is controlled by the global + variable Vreveal_ghoste_specifiers. It is not exposed to lisp, and + is set during calls to lisp functions which initialize global, + device and frame defaults, such as + init-{global,frame,device}-{faces,toolbars,etc}. + + Thus, values supplied by resources or other means of a window system + stored in externally unmodifiable ghost objects. Regular lisp code + may thus freely modify the normal part of a magic specifier, and + removing a specification for a particular domain causes the + specification to consider ghost-provided fallback values, or its own + fallback value. + + Rules of conduct for magic specifiers + ------------------------------------- + 1. All functions exposed to lisp operate on a ghost specifier when + Vreveal_ghoste_specifiers is non-nil. This includes both + modifying and non-modifying functions, such as + Fspecifier_instance, for symmetry and consistency. + 2. These functions deal with the above condition internally, passing + mangled specifier pointer to internal functions. The internal + functions always work on a specifier passed, and do not regard + the value of Vreveal_ghoste_specifiers. + 3. recompute_*() functions always operate on the whole specifier + when passed only a ghost object, by substituting it with their + parent bodily object. + 4. All specifier methods, except for instantiate method, are passed + the bodily object of the magic specifier. Instantiate method is + passed the specifier being instantiated. + 5. Only bodily objects are passed to set_specifier_caching function, + and only these may be cached. + 6. All specifiers are added to Vall_specifiers list, both bodily and + ghost. The pair of objects is always removed from the list at the + same time. +*/ + struct specifier_methods { CONST char *name; @@ -31,21 +91,36 @@ /* Implementation specific methods: */ - /* #### Document me */ - /* Create method */ + /* Create method: Initialize specifier data. Optional. */ void (*create_method) (Lisp_Object specifier); - /* Mark method */ + + /* Mark method: Mark any lisp object within specifier data + structure. Not required if no specifier data are Lisp_Objects. */ void (*mark_method) (Lisp_Object specifier, void (*markobj) (Lisp_Object)); - /* Equal method */ + + /* Equal method: Compare two specifiers. This is called after + ensuring that the two specifiers are of the same type, and habe + the same specs. Quit is inhibited during the call so it is safe + to call internal_equal(). + + If this function is not present, specifiers considered equal when + the above conditions are met, i.e. as if the method returned + non-zero. */ int (*equal_method) (Lisp_Object sp1, Lisp_Object sp2, int depth); - /* Hash method */ + + /* Hash method: Hash specifier instance data. This has to hash only + data structure of the specifier, as specs are hashed by the core + code. + + If this function is not present, hashing behaves as if it + returned zero. */ unsigned long (*hash_method) (Lisp_Object specifier, int depth); /* Validate method: Given an instantiator, verify that it's valid for this specifier type. If not, signal an error. - If this function is not present, all instantiators are - considered valid. */ + If this function is not present, all instantiators are considered + valid. */ void (*validate_method) (Lisp_Object instantiator); /* Validate-matchspec method: Given a matchspec, verify that it's @@ -55,15 +130,33 @@ valid. Note that this differs from validate_method(). */ void (*validate_matchspec_method) (Lisp_Object matchspec); - /* Instantiate method */ + /* Instantiate method: Return SPECIFIER instance in DOMAIN, + specified by INSTANTIATOR. MATCHSPEC specifies an additional + constraints on the instance value (see the docstring for + Fspecifier_matching_instance function). MATCHSPEC is passed + Qunbound when no matching constraints are imposed. The method is + called via call_with_suspended_errors(), so allowed to eval + safely. + + DEPTH is a lisp integer denoting current depth of instantiation + calls. #### WTF a method can do with this? + + This method must presume that both INSTANTIATOR and MATCSPEC are + already validated by the corresponding validate_* methods, and + may abort if they are invalid. + + Return value is an instance, which is returned immediately to the + caller, or Qunbound to continue instantiation lookup chain. + + If this function is not present, INSTANTIATOR is used as the + specifier instance. This is the usual case for "simple" + specifiers, like integer and boolean. */ Lisp_Object (*instantiate_method) (Lisp_Object specifier, Lisp_Object matchspec, Lisp_Object domain, Lisp_Object instantiator, - /* always an integer, but encapsulated - as a Lisp_Object so it can be called - from call_with_suspended_errors() */ Lisp_Object depth); + /* Going-to-add method: Called when an instantiator is about to be added to a specifier. This function can specify that different instantiators should be used instead by @@ -72,13 +165,21 @@ instantiator has been copied with copy-tree, so feel free to reuse parts of it to create a new instantiator. The tag-set, however, is not copied and is not canonicalized - (that will be done on the result of this function). - */ + (that will be done on the result of this function). */ Lisp_Object (*going_to_add_method) (Lisp_Object specifier, Lisp_Object locale, Lisp_Object tag_set, Lisp_Object instantiator); - /* After-change method */ + + /* After-change method: Called when the SPECIFIER has just been + changed in LOCALE. The method is called upon: + * Removing and adding specs to/from the specifier; + * Changing the specifier fallback. + + #### The method may have called more than once per each specifier + change. + + #### Do not still know if this can safely eval. */ void (*after_change_method) (Lisp_Object specifier, Lisp_Object locale); @@ -111,7 +212,16 @@ Lisp_Object buffer_specs; struct specifier_caching *caching; + + /* This can be either nil, for a plain, non-magic specifier object, + t for the normal part of the magic specifier, or #<specifier> for + the ghost part of the magic specifier, a pointer to its parent + object */ + Lisp_Object magic_parent; + + /* Fallback value. For magic specifiers, it is a pointer to the ghost. */ Lisp_Object fallback; + /* type-specific extra data attached to a specifier */ char data[1]; }; @@ -147,6 +257,13 @@ INLINE struct type##_specifier * \ error_check_##type##_specifier_data (struct Lisp_Specifier *sp) \ { \ + if (SPECIFIERP (sp->magic_parent)) \ + { \ + assert (SPECIFIER_TYPE_P (sp, type)); \ + sp = XSPECIFIER (sp->magic_parent); \ + } \ + else \ + assert (NILP (sp->magic_parent) || EQ (sp->magic_parent, Qt)); \ assert (SPECIFIER_TYPE_P (sp, type)); \ return (struct type##_specifier *) sp->data; \ } \ @@ -183,12 +300,35 @@ #define SPECIFIER_TYPE_P(sp, type) \ ((sp)->methods == type##_specifier_methods) +/* Any of the two of the magic spec */ +#define MAGIC_SPECIFIER_P(sp) \ + (!NILP((sp)->magic_parent)) +/* Normal part of the magic specifier */ +#define BODILY_SPECIFIER_P(sp) \ + (EQ ((sp)->magic_parent, Qt)) +/* Ghost part of the magic specifier */ +#define GHOST_SPECIFIER_P(sp) \ + (SPECIFIERP((sp)->magic_parent)) +/* The same three, when used in GC */ +#define GC_MAGIC_SPECIFIER_P(sp) \ + (!GC_NILP((sp)->magic_parent)) +#define GC_BODILY_SPECIFIER_P(sp) \ + (GC_EQ ((sp)->magic_parent, Qt)) +#define GC_GHOST_SPECIFIER_P(sp) \ + (GC_SPECIFIERP((sp)->magic_parent)) + +#define GHOST_SPECIFIER(sp) \ + (XSPECIFIER ((sp)->fallback)) + #ifdef ERROR_CHECK_TYPECHECK # define SPECIFIER_TYPE_DATA(sp, type) \ error_check_##type##_specifier_data (sp) #else -# define SPECIFIER_TYPE_DATA(sp, type) \ - ((struct type##_specifier *) (sp)->data) +# define SPECIFIER_TYPE_DATA(sp, type) \ + ((struct type##_specifier *) \ + (GHOST_SPECIFIER_P(sp) \ + ? XSPECIFIER((sp)->magic_parent)->data \ + : (sp)->data)) #endif /* #### Need to create ERROR_CHECKING versions of these. */ @@ -250,6 +390,7 @@ extern Lisp_Object Qfallback, Qnatnum; +Lisp_Object make_magic_specifier (Lisp_Object type); Lisp_Object decode_locale_list (Lisp_Object locale); extern enum spec_add_meth decode_how_to_add_specification (Lisp_Object how_to_add); @@ -271,6 +412,16 @@ void recompute_all_cached_specifiers_in_window (struct window *w); void recompute_all_cached_specifiers_in_frame (struct frame *f); +/* Counterparts of Fadd_spec_to_specifier and Fremove_specifier, + which operate directly on ghost objects */ +void add_spec_to_ghost_specifier (Lisp_Object specifier, Lisp_Object instantiator, + Lisp_Object locale, Lisp_Object tag_set, + Lisp_Object how_to_add); +void remove_ghost_specifier (Lisp_Object specifier, Lisp_Object locale, + Lisp_Object tag_set, Lisp_Object exact_p); + +int reveal_ghost_specifiers_protected (void); + void cleanup_specifiers (void); void prune_specifiers (int (*obj_marked_p) (Lisp_Object)); void setup_device_initial_specifier_tags (struct device *d);