+ Grob_property_info (context, context_property).pushpop
+ (grob_property_path, new_value);
+}
+
+bool
+typecheck_grob (SCM symbol, SCM value)
+{
+ if (Unpure_pure_container *upc = Unpure_pure_container::unsmob (value))
+ return typecheck_grob (symbol, upc->unpure_part ())
+ && typecheck_grob (symbol, upc->pure_part ());
+ return ly_is_procedure (value)
+ || Simple_closure::is_smob (value)
+ || type_check_assignment (symbol, value, ly_symbol2scm ("backend-type?"));
+}
+
+class Grob_properties : public Simple_smob<Grob_properties>
+{
+public:
+ SCM mark_smob ();
+ static const char type_p_name_[];
+private:
+ friend class Grob_property_info;
+ friend SCM ly_make_grob_properties (SCM);
+ // alist_ may contain unexpanded nested overrides
+ SCM alist_;
+ // based_on_ is the cooked_ value from the next higher context that
+ // alist_ is based on
+ SCM based_on_;
+ // cooked_ is a version of alist_ where nested overrides have been
+ // expanded
+ SCM cooked_;
+ // cooked_from_ is the value of alist_ from which the expansion has
+ // been done
+ SCM cooked_from_;
+ // nested_ is a count of nested overrides in alist_
+ int nested_;
+
+ Grob_properties (SCM alist, SCM based_on) :
+ alist_ (alist), based_on_ (based_on),
+ // if the constructor was called with lists possibly containing
+ // partial overrides, we would need to initialize with based_on in
+ // order to trigger an initial update. But this should never
+ // happen, so we initialize straight with alist.
+ cooked_ (alist), cooked_from_ (alist), nested_ (0) { }
+};
+
+const char Grob_properties::type_p_name_[] = "ly:grob-properties?";
+
+SCM
+Grob_properties::mark_smob ()
+{
+ scm_gc_mark (alist_);
+ scm_gc_mark (based_on_);
+ scm_gc_mark (cooked_);
+ return cooked_from_;
+}
+
+LY_DEFINE (ly_make_grob_properties, "ly:make-grob-properties",
+ 1, 0, 0, (SCM alist),
+ "This packages the given property list @var{alist} in"
+ " a grob property container stored in a context property"
+ " with the name of a grob.")
+{
+ LY_ASSERT_TYPE (ly_is_list, alist, 1);
+ return Grob_properties (alist, SCM_EOL).smobbed_copy ();
+}
+
+
+Grob_property_info
+Grob_property_info::find ()
+{
+ if (props_)
+ return *this;
+ SCM res = SCM_UNDEFINED;
+ if (Context *c = context_->where_defined (symbol_, &res))
+ if (c != context_)
+ return Grob_property_info (c, symbol_, Grob_properties::unsmob (res));
+ props_ = Grob_properties::unsmob (res);
+ return *this;
+}
+
+bool
+Grob_property_info::check ()
+{
+ if (props_)
+ return true;
+ SCM res = SCM_UNDEFINED;
+ if (context_->here_defined (symbol_, &res))
+ props_ = Grob_properties::unsmob (res);
+ return props_;