From 05ee69883965039ce7ec7189421a57c9ace7c5b5 Mon Sep 17 00:00:00 2001
From: hanwen <hanwen>
Date: Sat, 23 Jul 2005 01:24:27 +0000
Subject: [PATCH] * lily/include/translator.icc (ADD_ACKNOWLEDGER): new macro.

* lily/translator.cc (add_acknowledger): new file. Directly jump
into an Engraver::acknowledge_xxx () method based on a grobs
interface-list.

* lily/include/translator-dispatch-list.hh (class
Engraver_dispatch_list): new struct., new file.

* lily/engraver-group-engraver.cc (Engraver_group_engraver):
change acknowledgeHashTable to C++ member.
---
 ChangeLog                                  |  11 ++
 lily/accidental-engraver.cc                |  49 ++++--
 lily/ambitus-engraver.cc                   |  23 +--
 lily/arpeggio-engraver.cc                  |  62 +++++---
 lily/auto-beam-engraver.cc                 | 172 ++++++++++++---------
 lily/axis-group-engraver.cc                |   4 +-
 lily/bar-number-engraver.cc                |   6 +-
 lily/beam-engraver.cc                      |  99 ++++++------
 lily/break-align-engraver.cc               |   9 +-
 lily/chord-tremolo-engraver.cc             |  15 +-
 lily/clef-engraver.cc                      |  17 +-
 lily/cluster-engraver.cc                   |   7 +-
 lily/collision-engraver.cc                 |   8 +-
 lily/custos-engraver.cc                    |  57 +++----
 lily/dot-column-engraver.cc                |  23 ++-
 lily/drum-note-engraver.cc                 |  49 +++---
 lily/dynamic-engraver.cc                   |  93 +++++------
 lily/engraver-group-engraver.cc            |  50 ++++--
 lily/extender-engraver.cc                  |  26 ++--
 lily/fingering-engraver.cc                 |  32 ++--
 lily/font-size-engraver.cc                 |   7 +-
 lily/glissando-engraver.cc                 |  20 ++-
 lily/grid-line-span-engraver.cc            |  10 +-
 lily/grob-info.cc                          |  13 ++
 lily/grob-pq-engraver.cc                   |   6 +-
 lily/hara-kiri-engraver.cc                 |   4 +-
 lily/horizontal-bracket-engraver.cc        |  23 ++-
 lily/hyphen-engraver.cc                    |  21 ++-
 lily/include/axis-group-engraver.hh        |   2 +-
 lily/include/grob-info.hh                  |   5 +-
 lily/include/ligature-engraver.hh          |   4 +-
 lily/include/lily-proto.hh                 |   8 +
 lily/include/paper-column-engraver.hh      |   5 +-
 lily/include/staff-symbol-engraver.hh      |   2 +-
 lily/include/translator-dispatch-list.hh   |  35 +++++
 lily/include/translator.hh                 |  14 +-
 lily/include/translator.icc                |  17 +-
 lily/instrument-name-engraver.cc           |  29 ++--
 lily/key-engraver.cc                       |  28 ++--
 lily/ledger-line-engraver.cc               |  32 ++--
 lily/ligature-bracket-engraver.cc          |  24 +--
 lily/ligature-engraver.cc                  |  32 ++--
 lily/mark-engraver.cc                      |   9 +-
 lily/measure-grouping-engraver.cc          |  11 +-
 lily/moment.cc                             |   1 +
 lily/new-fingering-engraver.cc             |  90 +++++------
 lily/note-head-line-engraver.cc            |  33 ++--
 lily/ottava-engraver.cc                    |  14 +-
 lily/output-property-engraver.cc           |  10 +-
 lily/paper-column-engraver.cc              |  45 +++---
 lily/part-combine-engraver.cc              |  36 +++--
 lily/phrasing-slur-engraver.cc             | 112 ++++++++++----
 lily/piano-pedal-engraver.cc               |  25 ++-
 lily/pitched-trill-engraver.cc             |  38 +++--
 lily/rhythmic-column-engraver.cc           |  43 +++---
 lily/script-column-engraver.cc             |  10 +-
 lily/script-engraver.cc                    |  94 ++++++-----
 lily/separating-line-group-engraver.cc     |  11 +-
 lily/slur-engraver.cc                      |  99 ++++++++----
 lily/spacing-engraver.cc                   |  29 +++-
 lily/span-arpeggio-engraver.cc             |  10 +-
 lily/span-bar-engraver.cc                  |   7 +-
 lily/staff-collecting-engraver.cc          |  16 +-
 lily/staff-symbol-engraver.cc              |   4 +-
 lily/stem-engraver.cc                      |  49 +++---
 lily/system-start-delimiter-engraver.cc    |  53 ++++---
 lily/tab-staff-symbol-engraver.cc          |   3 +-
 lily/text-engraver.cc                      |  50 +++---
 lily/text-spanner-engraver.cc              |  10 +-
 lily/tie-engraver.cc                       |  71 ++++-----
 lily/translator-dispatch-list.cc           |  83 ++++++++++
 lily/translator.cc                         |   5 +-
 lily/vertical-align-engraver.cc            |   8 +-
 lily/vertically-spaced-context-engraver.cc |  13 +-
 lily/volta-engraver.cc                     |  62 ++++----
 75 files changed, 1368 insertions(+), 939 deletions(-)
 create mode 100644 lily/include/translator-dispatch-list.hh
 create mode 100644 lily/translator-dispatch-list.cc

diff --git a/ChangeLog b/ChangeLog
index 0598877d6d..aa338a3698 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2005-07-23  Han-Wen Nienhuys  <hanwen@xs4all.nl>
 
+ 	* lily/engraver*cc: use throughout.
+	
+	* lily/include/translator.icc (ADD_ACKNOWLEDGER): new macro.
+
+	* lily/translator.cc (add_acknowledger): new file. Directly jump
+	into an Engraver::acknowledge_xxx () method based on a grobs
+	interface-list.
+
+	* lily/include/translator-dispatch-list.hh (class
+	Engraver_dispatch_list): new struct., new file.
+
 	* scm/define-context-properties.scm
 	(all-internal-translation-properties): remove acceptHashTable,
 	acknowledgeHashTable
diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc
index 67402afcf2..be3d1b793c 100644
--- a/lily/accidental-engraver.cc
+++ b/lily/accidental-engraver.cc
@@ -56,7 +56,12 @@ class Accidental_engraver : public Engraver
 protected:
   TRANSLATOR_DECLARATIONS (Accidental_engraver);
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+
+  void acknowledge_tie (Grob_info);
+  void acknowledge_arpeggio (Grob_info);
+  void acknowledge_rhythmic_head (Grob_info);
+  void acknowledge_finger (Grob_info);
+  
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void initialize ();
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
@@ -544,13 +549,11 @@ Accidental_engraver::stop_translation_timestep ()
 }
 
 void
-Accidental_engraver::acknowledge_grob (Grob_info info)
+Accidental_engraver::acknowledge_rhythmic_head (Grob_info info)
 {
   Music *note = info.music_cause ();
-
   if (note
-      && note->is_mus_type ("note-event")
-      && Rhythmic_head::has_interface (info.grob ()))
+      && note->is_mus_type ("note-event"))
     {
       /*
 	String harmonics usually don't have accidentals.
@@ -568,13 +571,24 @@ Accidental_engraver::acknowledge_grob (Grob_info info)
 	  accidentals_.push (entry);
 	}
     }
-  else if (Tie::has_interface (info.grob ()))
-    ties_.push (dynamic_cast<Spanner *> (info.grob ()));
-  else if (Arpeggio::has_interface (info.grob ()))
-    left_objects_.push (info.grob ());
-  else if (info.grob ()
-	   ->internal_has_interface (ly_symbol2scm ("finger-interface")))
-    left_objects_.push (info.grob ());
+}
+
+void
+Accidental_engraver::acknowledge_tie (Grob_info info)
+{
+  ties_.push (dynamic_cast<Spanner *> (info.grob ()));
+}
+
+void
+Accidental_engraver::acknowledge_arpeggio (Grob_info info)
+{
+  left_objects_.push (info.grob ());
+}
+
+void
+Accidental_engraver::acknowledge_finger (Grob_info info)
+{
+  left_objects_.push (info.grob ());
 }
 
 void
@@ -587,6 +601,12 @@ Accidental_engraver::process_music ()
     update_local_key_signature ();
 }
 
+
+ADD_ACKNOWLEDGER(Accidental_engraver, arpeggio);
+ADD_ACKNOWLEDGER(Accidental_engraver, finger);
+ADD_ACKNOWLEDGER(Accidental_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER(Accidental_engraver, tie);
+
 ADD_TRANSLATOR (Accidental_engraver,
 		"Make accidentals.  "
 		"Catch note heads, ties and notices key-change events.  "
@@ -598,10 +618,7 @@ ADD_TRANSLATOR (Accidental_engraver,
 		"",
 		
 		/* acks */
-		"arpeggio-interface "
-		"finger-interface "
-		"rhythmic-head-interface "
-		"tie-interface ",
+		"",
 
 		"autoAccidentals "
 		"autoCautionaries "
diff --git a/lily/ambitus-engraver.cc b/lily/ambitus-engraver.cc
index 82f05c3974..e2471fc385 100644
--- a/lily/ambitus-engraver.cc
+++ b/lily/ambitus-engraver.cc
@@ -23,7 +23,7 @@ class Ambitus_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Ambitus_engraver);
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  void acknowledge_note_head (Grob_info);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
   virtual void derived_mark () const;
@@ -115,20 +115,13 @@ Ambitus_engraver::stop_translation_timestep ()
 }
 
 void
-Ambitus_engraver::acknowledge_grob (Grob_info info)
+Ambitus_engraver::acknowledge_note_head (Grob_info info)
 {
-  Item *item = dynamic_cast<Item *> (info.grob ());
-  if (item)
+  Music *nr = info.music_cause ();
+  if (nr && nr->is_mus_type ("note-event"))
     {
-      if (Note_head::has_interface (info.grob ()))
-	{
-	  Music *nr = info.music_cause ();
-	  if (nr && nr->is_mus_type ("note-event"))
-	    {
-	      Pitch pitch = *unsmob_pitch (nr->get_property ("pitch"));
-	      pitch_interval_.add_point (pitch);
-	    }
-	}
+      Pitch pitch = *unsmob_pitch (nr->get_property ("pitch"));
+      pitch_interval_.add_point (pitch);
     }
 }
 
@@ -187,12 +180,12 @@ Ambitus_engraver::finalize ()
     }
 }
 
-#include "translator.icc"
 
+ADD_ACKNOWLEDGER(Ambitus_engraver, note_head);
 ADD_TRANSLATOR (Ambitus_engraver,
 		/* descr */ "",
 		/* creats*/ "Ambitus AmbitusLine AmbitusNoteHead AmbitusAccidental",
 		/* accepts */ "",
-		/* acks  */ "note-head-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/arpeggio-engraver.cc b/lily/arpeggio-engraver.cc
index 856b5a7303..0e36185ba1 100644
--- a/lily/arpeggio-engraver.cc
+++ b/lily/arpeggio-engraver.cc
@@ -22,8 +22,10 @@ class Arpeggio_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Arpeggio_engraver);
 
+  void acknowledge_stem (Grob_info);
+  void acknowledge_rhythmic_head (Grob_info);
+  void acknowledge_note_column (Grob_info);
 protected:
-  virtual void acknowledge_grob (Grob_info);
   PRECOMPUTED_VIRTUAL void process_music ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual bool try_music (Music *);
@@ -49,32 +51,38 @@ Arpeggio_engraver::try_music (Music *m)
 }
 
 void
-Arpeggio_engraver::acknowledge_grob (Grob_info info)
+Arpeggio_engraver::acknowledge_stem (Grob_info info)
 {
   if (arpeggio_)
     {
-      if (Stem::has_interface (info.grob ()))
-	{
-	  if (!arpeggio_->get_parent (Y_AXIS))
-	    arpeggio_->set_parent (info.grob (), Y_AXIS);
-
-	  Pointer_group_interface::add_grob (arpeggio_,
-					     ly_symbol2scm ("stems"),
-					     info.grob ());
-	}
-
-      /*
-	We can't catch local key items (accidentals) from Voice context,
-	see Local_key_engraver
-      */
-      else if (Rhythmic_head::has_interface (info.grob ()))
-	{
-	  Side_position_interface::add_support (arpeggio_, info.grob ());
-	}
-      else if (Note_column::has_interface (info.grob ()))
-	{
-	  info.grob ()->set_object ("arpeggio", arpeggio_->self_scm ());
-	}
+      if (!arpeggio_->get_parent (Y_AXIS))
+	arpeggio_->set_parent (info.grob (), Y_AXIS);
+
+      Pointer_group_interface::add_grob (arpeggio_,
+					 ly_symbol2scm ("stems"),
+					 info.grob ());
+    }
+}
+void
+Arpeggio_engraver::acknowledge_rhythmic_head (Grob_info info)
+{
+  if (arpeggio_)
+
+    /*
+      We can't catch local key items (accidentals) from Voice context,
+      see Local_key_engraver
+    */
+    {
+      Side_position_interface::add_support (arpeggio_, info.grob ());
+    }
+}
+ 
+void
+Arpeggio_engraver::acknowledge_note_column (Grob_info info)
+{
+  if (arpeggio_)
+    {
+      info.grob ()->set_object ("arpeggio", arpeggio_->self_scm ());
     }
 }
 
@@ -94,10 +102,14 @@ Arpeggio_engraver::stop_translation_timestep ()
   arpeggio_event_ = 0;
 }
 
+ADD_ACKNOWLEDGER(Arpeggio_engraver, stem)
+ADD_ACKNOWLEDGER(Arpeggio_engraver, rhythmic_head)
+ADD_ACKNOWLEDGER(Arpeggio_engraver, note_column)
+
 ADD_TRANSLATOR (Arpeggio_engraver,
 		/* descr */ "Generate an Arpeggio symbol",
 		/* creats*/ "Arpeggio",
 		/* accepts */ "arpeggio-event",
-		/* acks  */ "stem-interface rhythmic-head-interface note-column-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc
index a83b635329..b05200a5f4 100644
--- a/lily/auto-beam-engraver.cc
+++ b/lily/auto-beam-engraver.cc
@@ -31,7 +31,12 @@ protected:
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual bool try_music (Music *);
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(rest);
+  DECLARE_ACKNOWLEDGER(beam);
+  DECLARE_ACKNOWLEDGER(bar_line);
+  DECLARE_ACKNOWLEDGER(stem);
+  
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
 
 private:
@@ -70,8 +75,26 @@ private:
   SCM beam_settings_;		// ugh. should protect ? 
 
   Beaming_info_list *finished_grouping_;
+
+  void check_bar_property ();
 };
 
+
+void
+Auto_beam_engraver::check_bar_property ()
+{
+  /* Duplicated from process_music (), since
+     Repeat_acknowledge_engraver::process_music () may also set whichBar.  */
+
+  Moment now = now_mom ();
+  if (scm_is_string (get_property ("whichBar"))
+      && beam_start_moment_ < now)
+    {
+      consider_end (shortest_mom_);
+      junk_beam ();
+    }
+}
+
 void
 Auto_beam_engraver::process_music ()
 {
@@ -277,95 +300,96 @@ Auto_beam_engraver::finalize ()
     junk_beam ();
 }
 
+
+
+
 void
-Auto_beam_engraver::acknowledge_grob (Grob_info info)
+Auto_beam_engraver::acknowledge_beam (Grob_info info)
 {
-  /* Duplicated from process_music (), since
-     Repeat_acknowledge_engraver::process_music () may also set whichBar.  */
-
-  Moment now = now_mom ();
-  if (scm_is_string (get_property ("whichBar"))
-      && beam_start_moment_ < now)
+  check_bar_property ();
+  if (stems_)
     {
-      consider_end (shortest_mom_);
-      junk_beam ();
+      end_beam ();
     }
+}
+ 
+void
+Auto_beam_engraver::acknowledge_bar_line (Grob_info info)
+{
+  check_bar_property ();
+  if (stems_)
+    end_beam ();
+}
 
+void
+Auto_beam_engraver::acknowledge_rest (Grob_info info)
+{
+  check_bar_property ();
   if (stems_)
+    end_beam ();
+}
+
+void
+Auto_beam_engraver::acknowledge_stem (Grob_info info)
+{
+  check_bar_property ();
+  Item *stem = dynamic_cast<Item *> (info.grob ());
+  Music *m = info.music_cause ();
+  if (!m->is_mus_type ("rhythmic-event"))
     {
-      if (Beam::has_interface (info.grob ()))
-	{
-	  end_beam ();
-	}
-      else if (Bar_line::has_interface (info.grob ()))
-	{
-	  end_beam ();
-	}
-      else if (Rest::has_interface (info.grob ()))
-	{
-	  end_beam ();
-	}
+      programming_error ("stem must have rhythmic structure");
+      return;
     }
 
-  if (Stem::has_interface (info.grob ()))
+  /*
+    Don't (start) auto-beam over empty stems; skips or rests
+  */
+  if (!Stem::head_count (stem))
     {
-      Item *stem = dynamic_cast<Item *> (info.grob ());
-      Music *m = info.music_cause ();
-      if (!m->is_mus_type ("rhythmic-event"))
-	{
-	  programming_error ("stem must have rhythmic structure");
-	  return;
-	}
-
-      /*
-	Don't (start) auto-beam over empty stems; skips or rests
-      */
-      if (!Stem::head_count (stem))
-	{
-	  if (stems_)
-	    end_beam ();
-	  return;
-	}
+      if (stems_)
+	end_beam ();
+      return;
+    }
 
-      if (Stem::get_beam (stem))
-	{
-	  if (stems_)
-	    junk_beam ();
-	  return;
-	}
+  if (Stem::get_beam (stem))
+    {
+      if (stems_)
+	junk_beam ();
+      return;
+    }
 
-      int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
+  int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
 
-      if (durlog <= 2)
-	{
-	  if (stems_)
-	    end_beam ();
-	  return;
-	}
+  if (durlog <= 2)
+    {
+      if (stems_)
+	end_beam ();
+      return;
+    }
 
-      /*
-	ignore grace notes.
-      */
-      if (bool (beam_start_location_.grace_part_) != bool (now.grace_part_))
-	return;
+  /*
+    ignore grace notes.
+  */
+  Moment now = now_mom ();
+  if (bool (beam_start_location_.grace_part_) != bool (now.grace_part_))
+    return;
 
-      Moment dur = unsmob_duration (m->get_property ("duration"))->get_length ();
+  Moment dur = unsmob_duration (m->get_property ("duration"))->get_length ();
 
-      consider_end (dur);
-      consider_begin (dur);
+  consider_end (dur);
+  consider_begin (dur);
 
-      if (dur < shortest_mom_)
-	shortest_mom_ = dur;
+  if (dur < shortest_mom_)
+    shortest_mom_ = dur;
 
-      if (!stems_)
-	return;
+  if (!stems_)
+    return;
 
-      grouping_->add_stem (now - beam_start_moment_ + beam_start_location_,
-			   durlog - 2);
-      stems_->push (stem);
-      last_add_mom_ = now;
-      extend_mom_ = max (extend_mom_, now) + m->get_length ();
-    }
+  grouping_->add_stem (now - beam_start_moment_ + beam_start_location_,
+		       durlog - 2);
+  stems_->push (stem);
+  last_add_mom_ = now;
+  extend_mom_ = max (extend_mom_, now) + m->get_length ();
 }
 
 void
@@ -399,6 +423,10 @@ Auto_beam_engraver::process_acknowledged ()
   process_acknowledged_count_++;
 }
 
+ADD_ACKNOWLEDGER(Auto_beam_engraver,stem);
+ADD_ACKNOWLEDGER(Auto_beam_engraver,bar_line);
+ADD_ACKNOWLEDGER(Auto_beam_engraver,beam);
+ADD_ACKNOWLEDGER(Auto_beam_engraver,rest);
 ADD_TRANSLATOR (Auto_beam_engraver,
 		/* descr */ "Generate beams based on measure characteristics and observed "
 		"Stems.  Uses beatLength, measureLength and measurePosition to decide "
@@ -407,6 +435,6 @@ ADD_TRANSLATOR (Auto_beam_engraver,
 		"@code{stemRightBeamCount}. ",
 		/* creats*/ "Beam",
 		/* accepts */ "beam-forbid-event",
-		/* acks  */ "stem-interface rest-interface beam-interface bar-line-interface",
+		/* acks  */ "",
 		/* reads */ "autoBeaming autoBeamSettings beatLength subdivideBeams",
 		/* write */ "");
diff --git a/lily/axis-group-engraver.cc b/lily/axis-group-engraver.cc
index 105c925397..69b77683b6 100644
--- a/lily/axis-group-engraver.cc
+++ b/lily/axis-group-engraver.cc
@@ -121,10 +121,12 @@ Axis_group_engraver::add_element (Grob *e)
   Axis_group_interface::add_element (staffline_, e);
 }
 
+ADD_ACKNOWLEDGER(Axis_group_engraver, grob);
+
 ADD_TRANSLATOR (Axis_group_engraver,
 		/* descr */ "Group all objects created in this context in a VerticalAxisGroup spanner.",
 		/* creats*/ "VerticalAxisGroup",
 		/* accepts */ "",
-		/* acks  */ "grob-interface",
+		/* acks  */ "",
 		/* reads */ "verticalExtent minimumVerticalExtent extraVerticalExtent",
 		/* write */ "");
diff --git a/lily/bar-number-engraver.cc b/lily/bar-number-engraver.cc
index 7fc92c0a5d..66fbe687e4 100644
--- a/lily/bar-number-engraver.cc
+++ b/lily/bar-number-engraver.cc
@@ -27,7 +27,7 @@ protected:
   Item *text_;
 protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(break_aligned);
   PRECOMPUTED_VIRTUAL void process_music ();
   void create_items ();
   TRANSLATOR_DECLARATIONS (Bar_number_engraver);
@@ -65,7 +65,7 @@ Bar_number_engraver::Bar_number_engraver ()
 }
 
 void
-Bar_number_engraver::acknowledge_grob (Grob_info inf)
+Bar_number_engraver::acknowledge_break_aligned (Grob_info inf)
 {
   Grob *s = inf.grob ();
   if (text_
@@ -108,6 +108,6 @@ ADD_TRANSLATOR (Bar_number_engraver,
 
 		/* creats*/ "BarNumber",
 		/* accepts */ "",
-		/* acks  */ "break-aligned-interface",
+		/* acks  */ "",
 		/* reads */ "currentBarNumber stavesFound barNumberVisibility",
 		/* write */ "");
diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc
index da3354134a..f1738796ed 100644
--- a/lily/beam-engraver.cc
+++ b/lily/beam-engraver.cc
@@ -23,6 +23,9 @@
 
 class Beam_engraver : public Engraver
 {
+public:
+  DECLARE_ACKNOWLEDGER(stem);
+  DECLARE_ACKNOWLEDGER(rest);
 protected:
   Music *start_ev_;
 
@@ -52,7 +55,6 @@ protected:
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
   virtual void finalize ();
 
-  virtual void acknowledge_grob (Grob_info);
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void process_music ();
 
@@ -216,66 +218,69 @@ Beam_engraver::finalize ()
 }
 
 void
-Beam_engraver::acknowledge_grob (Grob_info info)
+Beam_engraver::acknowledge_rest (Grob_info info)
+{
+  if (beam_)
+    info.grob ()->add_offset_callback (Beam::rest_collision_callback_proc, Y_AXIS);
+}
+
+void
+Beam_engraver::acknowledge_stem (Grob_info info)
 {
   if (beam_)
     {
-      if (Rest::has_interface (info.grob ()))
+      Moment now = now_mom ();
+
+      if (!valid_start_point ())
+	return;
+
+      Item *stem = dynamic_cast<Item *> (info.grob ());
+      if (Stem::get_beam (stem))
+	return;
+
+      Music *m = info.music_cause ();
+      if (!m->is_mus_type ("rhythmic-event"))
 	{
-	  info.grob ()->add_offset_callback (Beam::rest_collision_callback_proc, Y_AXIS);
+	  String s = _ ("stem must have Rhythmic structure");
+	  if (info.music_cause ())
+	    info.music_cause ()->origin ()->warning (s);
+	  else
+	    ::warning (s);
+
+	  return;
 	}
-      else if (Stem::has_interface (info.grob ()))
+
+      last_stem_added_at_ = now;
+      int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
+      if (durlog <= 2)
 	{
-	  Moment now = now_mom ();
-
-	  if (!valid_start_point ())
-	    return;
-
-	  Item *stem = dynamic_cast<Item *> (info.grob ());
-	  if (Stem::get_beam (stem))
-	    return;
-
-	  Music *m = info.music_cause ();
-	  if (!m->is_mus_type ("rhythmic-event"))
-	    {
-	      String s = _ ("stem must have Rhythmic structure");
-	      if (info.music_cause ())
-		info.music_cause ()->origin ()->warning (s);
-	      else
-		::warning (s);
-
-	      return;
-	    }
-
-	  last_stem_added_at_ = now;
-	  int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
-	  if (durlog <= 2)
-	    {
-	      m->origin ()->warning (_ ("stem doesn't fit in beam"));
-	      prev_start_ev_->origin ()->warning (_ ("beam was started here"));
-	      /*
-		don't return, since
-
-		[r4 c8] can just as well be modern notation.
-	      */
-	    }
-
-	  stem->set_property ("duration-log",
-			      scm_int2num (durlog));
-	  Moment stem_location = now - beam_start_mom_ + beam_start_location_;
-	  beam_info_->add_stem (stem_location,
-				max (durlog- 2, 0));
-	  Beam::add_stem (beam_, stem);
+	  m->origin ()->warning (_ ("stem doesn't fit in beam"));
+	  prev_start_ev_->origin ()->warning (_ ("beam was started here"));
+	  /*
+	    don't return, since
+
+	    [r4 c8] can just as well be modern notation.
+	  */
 	}
+
+      stem->set_property ("duration-log",
+			  scm_int2num (durlog));
+      Moment stem_location = now - beam_start_mom_ + beam_start_location_;
+      beam_info_->add_stem (stem_location,
+			    max (durlog- 2, 0));
+      Beam::add_stem (beam_, stem);
     }
 }
 
+ADD_ACKNOWLEDGER(Beam_engraver, stem);
+ADD_ACKNOWLEDGER(Beam_engraver, rest);
+
 ADD_TRANSLATOR (Beam_engraver,
 		/* descr */ "Handles Beam events by engraving Beams.    If omitted, then notes will be "
 		"printed with flags instead of beams.",
 		/* creats*/ "Beam",
 		/* accepts */ "beam-event",
-		/* acks  */ "stem-interface rest-interface",
+		/* acks  */ "",
 		/* reads */ "beamMelismaBusy beatLength subdivideBeams",
 		/* write */ "");
 
@@ -307,6 +312,8 @@ Grace_beam_engraver::valid_end_point ()
   return beam_ && valid_start_point ();
 }
 
+ADD_ACKNOWLEDGER(Grace_beam_engraver, stem);
+ADD_ACKNOWLEDGER(Grace_beam_engraver, rest);
 ADD_TRANSLATOR (Grace_beam_engraver,
 		/* descr */ "Handles Beam events by engraving Beams.  If omitted, then notes will "
 		"be printed with flags instead of beams. Only engraves beams when we "
diff --git a/lily/break-align-engraver.cc b/lily/break-align-engraver.cc
index affc8a63a0..2363fdded0 100644
--- a/lily/break-align-engraver.cc
+++ b/lily/break-align-engraver.cc
@@ -23,11 +23,12 @@ class Break_align_engraver : public Engraver
 
   void add_to_group (SCM, Item *);
 protected:
-  virtual void acknowledge_grob (Grob_info i);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void derived_mark () const;
 public:
   TRANSLATOR_DECLARATIONS (Break_align_engraver);
+  DECLARE_ACKNOWLEDGER(break_aligned);
+
 };
 
 void
@@ -53,7 +54,7 @@ Break_align_engraver::derived_mark () const
 }
 
 void
-Break_align_engraver::acknowledge_grob (Grob_info inf)
+Break_align_engraver::acknowledge_break_aligned (Grob_info inf)
 {
   if (Item *item = dynamic_cast<Item *> (inf.grob ()))
     {
@@ -120,13 +121,13 @@ Break_align_engraver::add_to_group (SCM align_name, Item *item)
     }
   Axis_group_interface::add_element (group, item);
 }
-
+ADD_ACKNOWLEDGER(Break_align_engraver, break_aligned);
 ADD_TRANSLATOR (Break_align_engraver,
 		"Align grobs with corresponding @code{break-align-symbols} into "
 		"groups, and order the groups according to @code{breakAlignOrder}. "
 		"The left edge of the alignment gets a separate group, with a symbol @code{left-edge}. ",
 		/* creats*/ "BreakAlignment BreakAlignGroup LeftEdge",
 		/* accepts */ "",
-		/* acks  */ "break-aligned-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/chord-tremolo-engraver.cc b/lily/chord-tremolo-engraver.cc
index 7bb5d93a2b..d4221afd20 100644
--- a/lily/chord-tremolo-engraver.cc
+++ b/lily/chord-tremolo-engraver.cc
@@ -19,6 +19,8 @@
 #include "stem-tremolo.hh"
 #include "math.h" // ceil
 
+#include "translator.icc"
+
 /**
 
 This acknowledges repeated music with "tremolo" style.  It typesets
@@ -56,10 +58,10 @@ protected:
 protected:
   virtual void finalize ();
   virtual bool try_music (Music *);
-  virtual void acknowledge_grob (Grob_info);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
+  DECLARE_ACKNOWLEDGER(stem);
 };
 
 Chord_tremolo_engraver::Chord_tremolo_engraver ()
@@ -139,9 +141,9 @@ Chord_tremolo_engraver::typeset_beam ()
 }
 
 void
-Chord_tremolo_engraver::acknowledge_grob (Grob_info info)
+Chord_tremolo_engraver::acknowledge_stem (Grob_info info)
 {
-  if (beam_ && Stem::has_interface (info.grob ()))
+  if (beam_)
     {
       Grob *s = info.grob ();
 
@@ -170,8 +172,7 @@ Chord_tremolo_engraver::acknowledge_grob (Grob_info info)
     }
   else if (repeat_
 	   && flags_
-	   && !body_is_sequential_
-	   && Stem::has_interface (info.grob ()))
+	   && !body_is_sequential_)
     {
       stem_tremolo_ = make_item ("StemTremolo", repeat_->self_scm ());
       stem_tremolo_->set_property ("flag-count",
@@ -207,12 +208,12 @@ Chord_tremolo_engraver::stop_translation_timestep ()
   typeset_beam ();
 }
 
-#include "translator.icc"
 
+ADD_ACKNOWLEDGER(Chord_tremolo_engraver,stem);
 ADD_TRANSLATOR (Chord_tremolo_engraver,
 		/* descr */ "Generates beams for  tremolo repeats.",
 		/* creats*/ "Beam",
 		/* accepts */ "repeated-music",
-		/* acks  */ "stem-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/clef-engraver.cc b/lily/clef-engraver.cc
index 090647ae71..99b92bd5e4 100644
--- a/lily/clef-engraver.cc
+++ b/lily/clef-engraver.cc
@@ -17,6 +17,8 @@
 #include "direction.hh"
 #include "side-position-interface.hh"
 
+#include "translator.icc"
+
 class Clef_engraver : public Engraver
 {
 public:
@@ -27,7 +29,7 @@ public:
 protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(bar_line);
 private:
   Item *clef_;
   Item *octavate_;
@@ -69,14 +71,12 @@ Clef_engraver::set_glyph ()
    ie. a breakpoint)
 */
 void
-Clef_engraver::acknowledge_grob (Grob_info info)
+Clef_engraver::acknowledge_bar_line (Grob_info info)
 {
   Item *item = dynamic_cast<Item *> (info.grob ());
-  if (item)
+  if (item && scm_is_string (get_property ("clefGlyph")))
     {
-      if (Bar_line::has_interface (info.grob ())
-	  && scm_is_string (get_property ("clefGlyph")))
-	create_clef ();
+      create_clef ();
     }
 }
 
@@ -182,12 +182,11 @@ Clef_engraver::stop_translation_timestep ()
     }
 }
 
-#include "translator.icc"
-
+ADD_ACKNOWLEDGER(Clef_engraver, bar_line);
 ADD_TRANSLATOR (Clef_engraver,
 		/* descr */ "Determine and set reference point for pitches",
 		/* creats*/ "Clef OctavateEight",
 		/* accepts */ "",
-		/* acks  */ "bar-line-interface",
+		/* acks  */ "",
 		/* reads */ "clefPosition clefGlyph middleCPosition clefOctavation explicitClefVisibility forceClef",
 		/* write */ "");
diff --git a/lily/cluster-engraver.cc b/lily/cluster-engraver.cc
index b64e80f8fb..cbab361ca6 100644
--- a/lily/cluster-engraver.cc
+++ b/lily/cluster-engraver.cc
@@ -20,7 +20,7 @@ protected:
   TRANSLATOR_DECLARATIONS (Cluster_spanner_engraver);
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
 private:
@@ -116,7 +116,7 @@ Cluster_spanner_engraver::stop_translation_timestep ()
 }
 
 void
-Cluster_spanner_engraver::acknowledge_grob (Grob_info info)
+Cluster_spanner_engraver::acknowledge_note_column (Grob_info info)
 {
   if (!beacon_ && Note_column::has_interface (info.grob ()))
     {
@@ -127,11 +127,12 @@ Cluster_spanner_engraver::acknowledge_grob (Grob_info info)
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Cluster_spanner_engraver, note_column);
 ADD_TRANSLATOR (Cluster_spanner_engraver,
 		/* descr */	"Engraves a cluster using Spanner notation ",
 		/* creats*/	"ClusterSpanner ClusterSpannerBeacon",
 		/* accepts */	"cluster-note-event busy-playing-event",
-		/* acks  */	"note-column-interface",
+		/* acks  */	"",
 		/* reads */	"",
 		/* write */	"");
 
diff --git a/lily/collision-engraver.cc b/lily/collision-engraver.cc
index 0c5b63b89c..4ddf5f6e06 100644
--- a/lily/collision-engraver.cc
+++ b/lily/collision-engraver.cc
@@ -18,7 +18,7 @@ class Collision_engraver : public Engraver
   Link_array<Grob> note_columns_;
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 public:
@@ -40,7 +40,7 @@ Collision_engraver::process_acknowledged ()
 }
 
 void
-Collision_engraver::acknowledge_grob (Grob_info i)
+Collision_engraver::acknowledge_note_column (Grob_info i)
 {
   if (Note_column::has_interface (i.grob ()))
     {
@@ -66,10 +66,12 @@ Collision_engraver::Collision_engraver ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Collision_engraver, note_column);
+
 ADD_TRANSLATOR (Collision_engraver,
 		/* descr */ "Collect NoteColumns, and as soon as there are two or more, put them in a NoteCollision object.",
 		/* creats*/ "NoteCollision",
 		/* accepts */ "",
-		/* acks  */ "note-column-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/custos-engraver.cc b/lily/custos-engraver.cc
index 4343d696f8..2bf02392ff 100644
--- a/lily/custos-engraver.cc
+++ b/lily/custos-engraver.cc
@@ -15,6 +15,8 @@
 #include "warn.hh"
 #include "pitch.hh"
 
+#include "translator.icc"
+
 
 /*
  * This class implements an engraver for custos symbols.
@@ -27,21 +29,22 @@ class Custos_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Custos_engraver);
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(bar);
+  DECLARE_ACKNOWLEDGER(note_head);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
 
 private:
   Item *create_custos ();
-  bool custos_permitted;
+  bool custos_permitted_;
   Link_array<Grob> custodes_;
   Array<Pitch> pitches_;
 };
 
 Custos_engraver::Custos_engraver ()
 {
-  custos_permitted = false;
+  custos_permitted_ = false;
 }
 
 void
@@ -52,7 +55,7 @@ Custos_engraver::stop_translation_timestep ()
   */
   pitches_.clear ();
 
-  custos_permitted = false;
+  custos_permitted_ = false;
 }
 
 void
@@ -62,29 +65,27 @@ Custos_engraver::start_translation_timestep ()
 }
 
 void
-Custos_engraver::acknowledge_grob (Grob_info info)
+Custos_engraver::acknowledge_bar (Grob_info info)
+{
+  custos_permitted_ = true;
+}
+
+void
+Custos_engraver::acknowledge_note_head (Grob_info info)
 {
-  Item *item = dynamic_cast<Item *> (info.grob ());
-  if (item)
+  Music *m = info.music_cause ();
+  if (m && m->is_mus_type ("note-event"))
     {
-      Music *m = info.music_cause ();
-      if (Bar_line::has_interface (info.grob ()))
-	custos_permitted = true;
-      else if (Note_head::has_interface (info.grob ())
-	       && m
-	       && m->is_mus_type ("note-event"))
-	{
 
-	  /*
-	    ideally, we'd do custos->set_parent (Y_AXIS, notehead),
-	    but since the note head lives on the other system, we can't
+      /*
+	ideally, we'd do custos->set_parent (Y_AXIS, notehead),
+	but since the note head lives on the other system, we can't
 
-	    So we copy the position from the note head pitch.  We
-	    don't look at the staff-position, since we can't be sure
-	    whether Clef_engraver already applied a vertical shift.
-	  */
-	  pitches_.push (*unsmob_pitch (m->get_property ("pitch")));
-	}
+	So we copy the position from the note head pitch.  We
+	don't look at the staff-position, since we can't be sure
+	whether Clef_engraver already applied a vertical shift.
+      */
+      pitches_.push (*unsmob_pitch (m->get_property ("pitch")));
     }
 }
 
@@ -92,9 +93,9 @@ void
 Custos_engraver::process_acknowledged ()
 {
   if (scm_is_string (get_property ("whichBar")))
-    custos_permitted = true;
+    custos_permitted_ = true;
 
-  if (custos_permitted)
+  if (custos_permitted_)
     {
       for (int i = pitches_.size (); i--;)
 	{
@@ -133,12 +134,14 @@ Custos_engraver::finalize ()
   custodes_.clear ();
 }
 
-#include "translator.icc"
+
+ADD_ACKNOWLEDGER(Custos_engraver,bar);
+ADD_ACKNOWLEDGER(Custos_engraver,note_head);
 
 ADD_TRANSLATOR (Custos_engraver,
 		/* descr */ "",
 		/* creats*/ "Custos",
 		/* accepts */ "",
-		/* acks  */ "bar-line-interface note-head-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/dot-column-engraver.cc b/lily/dot-column-engraver.cc
index 48b4500600..b6580204e0 100644
--- a/lily/dot-column-engraver.cc
+++ b/lily/dot-column-engraver.cc
@@ -11,6 +11,7 @@
 #include "side-position-interface.hh"
 #include "engraver.hh"
 #include "stem.hh"
+#include "translator.icc"
 
 class Dot_column_engraver : public Engraver
 {
@@ -21,7 +22,10 @@ public:
   TRANSLATOR_DECLARATIONS (Dot_column_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(stem);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
+  
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
 
@@ -48,7 +52,7 @@ Dot_column_engraver::stop_translation_timestep ()
 }
 
 void
-Dot_column_engraver::acknowledge_grob (Grob_info info)
+Dot_column_engraver::acknowledge_rhythmic_head (Grob_info info)
 {
   Grob *d = unsmob_grob (info.grob ()->get_object ("dot"));
   if (d)
@@ -60,19 +64,22 @@ Dot_column_engraver::acknowledge_grob (Grob_info info)
 
       Dot_column::add_head (dotcol_, info.grob ());
     }
-  else if (Stem::has_interface (info.grob ()))
-    {
-      stem_ = info.grob ();
-    }
 }
 
-#include "translator.icc"
 
+void
+Dot_column_engraver::acknowledge_stem (Grob_info info)
+{
+  stem_ = info.grob ();
+}
+
+ADD_ACKNOWLEDGER(Dot_column_engraver, stem);
+ADD_ACKNOWLEDGER(Dot_column_engraver, rhythmic_head);
 ADD_TRANSLATOR (Dot_column_engraver,
 		/* descr */ "Engraves dots on dotted notes shifted to the right of the note.\n"
 		"If omitted, then dots appear on top of the notes.",
 		/* creats*/ "DotColumn",
 		/* accepts */ "",
-		/* acks  */ "rhythmic-head-interface dot-column-interface stem-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/drum-note-engraver.cc b/lily/drum-note-engraver.cc
index e88fd5e530..cf61692baa 100644
--- a/lily/drum-note-engraver.cc
+++ b/lily/drum-note-engraver.cc
@@ -28,7 +28,8 @@ public:
 protected:
   virtual bool try_music (Music *ev);
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(stem);
+  DECLARE_ACKNOWLEDGER(note_column);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
 
@@ -120,35 +121,33 @@ Drum_notes_engraver::process_music ()
 }
 
 void
-Drum_notes_engraver::acknowledge_grob (Grob_info inf)
+Drum_notes_engraver::acknowledge_stem (Grob_info inf)
 {
-  if (Stem::has_interface (inf.grob ()))
+  for (int i = 0; i < scripts_.size (); i++)
     {
-      for (int i = 0; i < scripts_.size (); i++)
-	{
-	  Grob *e = scripts_[i];
+      Grob *e = scripts_[i];
 
-	  if (to_dir (e->get_property ("side-relative-direction")))
-	    e->set_object ("direction-source", inf.grob ()->self_scm ());
+      if (to_dir (e->get_property ("side-relative-direction")))
+	e->set_object ("direction-source", inf.grob ()->self_scm ());
 
-	  /*
-	    add dep ?
-	  */
-	  e->add_dependency (inf.grob ());
-	  Side_position_interface::add_support (e, inf.grob ());
-	}
+      /*
+	add dep ?
+      */
+      e->add_dependency (inf.grob ());
+      Side_position_interface::add_support (e, inf.grob ());
     }
-  else if (Note_column::has_interface (inf.grob ()))
+}
+void
+Drum_notes_engraver::acknowledge_note_column (Grob_info inf)
+{
+  for (int i = 0; i < scripts_.size (); i++)
     {
-      for (int i = 0; i < scripts_.size (); i++)
-	{
-	  Grob *e = scripts_[i];
+      Grob *e = scripts_[i];
 
-	  if (!e->get_parent (X_AXIS)
-	      && Side_position_interface::get_axis (e) == Y_AXIS)
-	    {
-	      e->set_parent (inf.grob (), X_AXIS);
-	    }
+      if (!e->get_parent (X_AXIS)
+	  && Side_position_interface::get_axis (e) == Y_AXIS)
+	{
+	  e->set_parent (inf.grob (), X_AXIS);
 	}
     }
 }
@@ -165,11 +164,13 @@ Drum_notes_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Drum_notes_engraver, stem);
+ADD_ACKNOWLEDGER(Drum_notes_engraver,note_column);
 ADD_TRANSLATOR (Drum_notes_engraver,
 		/* descr */ "Generate noteheads.",
 		/* creats*/ "NoteHead Dots Script",
 		/* accepts */ "note-event busy-playing-event",
-		/* acks  */ "stem-interface note-column-interface",
+		/* acks  */ "",
 		/* reads */ "drumStyleTable",
 		/* write */ "");
 
diff --git a/lily/dynamic-engraver.cc b/lily/dynamic-engraver.cc
index db9e5fa048..fc5c2ebefc 100644
--- a/lily/dynamic-engraver.cc
+++ b/lily/dynamic-engraver.cc
@@ -22,6 +22,8 @@
 #include "self-alignment-interface.hh"
 #include "pointer-group-interface.hh"
 
+#include "translator.icc"
+
 /*
   TODO:
 
@@ -58,10 +60,12 @@ class Dynamic_engraver : public Engraver
   void typeset_all ();
 
   TRANSLATOR_DECLARATIONS (Dynamic_engraver);
+  DECLARE_ACKNOWLEDGER(script);
+  DECLARE_ACKNOWLEDGER(note_column);
+
 
 protected:
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
   virtual bool try_music (Music *event);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -366,66 +370,69 @@ Dynamic_engraver::typeset_all ()
 }
 
 void
-Dynamic_engraver::acknowledge_grob (Grob_info info)
+Dynamic_engraver::acknowledge_note_column (Grob_info info)
 {
   if (!line_spanner_)
     return;
 
-  if (Note_column::has_interface (info.grob ()))
+  if (line_spanner_
+      /* Don't refill killed spanner */
+      && line_spanner_->is_live ())
     {
-      if (line_spanner_
-	  /* Don't refill killed spanner */
-	  && line_spanner_->is_live ())
-	{
-	  Side_position_interface::add_support (line_spanner_, info.grob ());
-	  add_bound_item (line_spanner_, dynamic_cast<Item *> (info.grob ()));
-	}
+      Side_position_interface::add_support (line_spanner_, info.grob ());
+      add_bound_item (line_spanner_, dynamic_cast<Item *> (info.grob ()));
+    }
 
-      if (script_ && !script_->get_parent (X_AXIS))
+  if (script_ && !script_->get_parent (X_AXIS))
+    {
+      extract_grob_set (info.grob (), "note-heads", heads);
+      if (heads.size())
 	{
-	  extract_grob_set (info.grob (), "note-heads", heads);
-	  if (heads.size())
-	    {
-	      Grob *head = heads[0];
-	      script_->set_parent (head, X_AXIS);
-	      script_->add_offset_callback (Self_alignment_interface::centered_on_parent_proc,
-					    X_AXIS);
+	  Grob *head = heads[0];
+	  script_->set_parent (head, X_AXIS);
+	  script_->add_offset_callback (Self_alignment_interface::centered_on_parent_proc,
+					X_AXIS);
 
-	    }
-	}
-
-      if (cresc_)
-	{
-	  if (!cresc_->get_bound (LEFT))
-	    {
-	      cresc_->set_bound (LEFT, info.grob ());
-	      add_bound_item (line_spanner_, cresc_->get_bound (LEFT));
-	    }
 	}
+    }
 
-      if (finished_cresc_ && !finished_cresc_->get_bound (RIGHT))
+  if (cresc_)
+    {
+      if (!cresc_->get_bound (LEFT))
 	{
-	  finished_cresc_->set_bound (RIGHT, info.grob ());
+	  cresc_->set_bound (LEFT, info.grob ());
+	  add_bound_item (line_spanner_, cresc_->get_bound (LEFT));
 	}
     }
-  
-  else if (Script_interface::has_interface (info.grob ()) && script_)
+
+  if (finished_cresc_ && !finished_cresc_->get_bound (RIGHT))
     {
-      SCM p = info.grob ()->get_property ("script-priority");
+      finished_cresc_->set_bound (RIGHT, info.grob ());
+    }
+}
 
-      /*
-	UGH.
+void
+Dynamic_engraver::acknowledge_script (Grob_info info)
+{
+  if (!line_spanner_ || !script_)
+    return;
 
-	DynamicText doesn't really have a script-priority field.
-      */
-      if (scm_is_number (p)
-	  && scm_to_int (p)
-	  < scm_to_int (script_->get_property ("script-priority")))
-	Side_position_interface::add_support (line_spanner_, info.grob ());
-    }
+  SCM p = info.grob ()->get_property ("script-priority");
+
+  /*
+    UGH.
+
+    DynamicText doesn't really have a script-priority field.
+  */
+  if (scm_is_number (p)
+      && scm_to_int (p)
+      < scm_to_int (script_->get_property ("script-priority")))
+    Side_position_interface::add_support (line_spanner_, info.grob ());
 }
 
-#include "translator.icc"
+
+ADD_ACKNOWLEDGER(Dynamic_engraver,script);
+ADD_ACKNOWLEDGER(Dynamic_engraver,note_column);
 
 ADD_TRANSLATOR (Dynamic_engraver,
 		/* descr */
diff --git a/lily/engraver-group-engraver.cc b/lily/engraver-group-engraver.cc
index 6584aefed5..20d2b87f4b 100644
--- a/lily/engraver-group-engraver.cc
+++ b/lily/engraver-group-engraver.cc
@@ -8,11 +8,11 @@
 
 #include "engraver-group-engraver.hh"
 
-#include "flower-proto.hh"
 #include "warn.hh"
 #include "paper-score.hh"
 #include "grob.hh"
 #include "context.hh"
+#include "translator-dispatch-list.hh"
 
 void
 Engraver_group_engraver::announce_grob (Grob_info info)
@@ -62,22 +62,47 @@ Engraver_group_engraver::acknowledge_grobs ()
 	}
 
       SCM acklist = scm_hashq_ref (acknowledge_hash_table_, nm, SCM_UNDEFINED);
+      Engraver_dispatch_list *dispatch
+	= Engraver_dispatch_list::unsmob (acklist);
+
       if (acklist == SCM_BOOL_F)
 	{
-	  acklist = find_acknowledge_engravers (get_simple_trans_list (), meta);
-	  scm_hashq_set_x (acknowledge_hash_table_, nm, acklist);
+	  SCM ifaces
+	    = scm_cdr (scm_assoc (ly_symbol2scm ("interfaces"), meta));
+	  acklist = Engraver_dispatch_list::create (get_simple_trans_list (),
+						      ifaces);
+
+	  dispatch
+	    = Engraver_dispatch_list::unsmob (acklist);
+
+	  if (dispatch)
+	    scm_hashq_set_x (acknowledge_hash_table_, nm, acklist);
 	}
 
-      for (SCM p = acklist; scm_is_pair (p); p = scm_cdr (p))
+
+      if (dispatch)
 	{
-	  Translator *t = unsmob_translator (scm_car (p));
-	  Engraver *eng = dynamic_cast<Engraver *> (t);
-	  if (eng && eng != info.origin_translator ())
-	    eng->acknowledge_grob (info);
+	  dispatch->apply (info);
+	}
+      else
+	{
+	  if (acklist == SCM_BOOL_F)
+	    {
+	      acklist = find_acknowledge_engravers (get_simple_trans_list (),
+						    meta);
+	      scm_hashq_set_x (acknowledge_hash_table_, nm, acklist);
+	    }
+
+	  for (SCM p = acklist; scm_is_pair (p); p = scm_cdr (p))
+	    {
+	      Translator *t = unsmob_translator (scm_car (p));
+	      Engraver *eng = dynamic_cast<Engraver *> (t);
+	      if (eng && eng != info.origin_translator ())
+		eng->acknowledge_grob (info);
+	    }
 	}
     }
 }
-
 /*
   Ugh. This is slightly expensive. We could/should cache the value of
   the group count?
@@ -148,7 +173,8 @@ ADD_TRANSLATOR_GROUP (Engraver_group_engraver,
 bool
 engraver_valid (Translator *tr, SCM ifaces)
 {
-  SCM ack_ifs = scm_assoc (ly_symbol2scm ("interfaces-acked"), tr->translator_description ());
+  SCM ack_ifs = scm_assoc (ly_symbol2scm ("interfaces-acked"),
+			   tr->translator_description ());
   ack_ifs = scm_cdr (ack_ifs);
   for (SCM s = ifaces; scm_is_pair (s); s = scm_cdr (s))
     if (scm_c_memq (scm_car (s), ack_ifs) != SCM_BOOL_F)
@@ -157,10 +183,8 @@ engraver_valid (Translator *tr, SCM ifaces)
 }
 
 SCM
-find_acknowledge_engravers (SCM gravlist, SCM meta_alist)
+find_acknowledge_engravers (SCM gravlist, SCM ifaces)
 {
-  SCM ifaces = scm_cdr (scm_assoc (ly_symbol2scm ("interfaces"), meta_alist));
-
   SCM l = SCM_EOL;
   for (SCM s = gravlist; scm_is_pair (s); s = scm_cdr (s))
     {
diff --git a/lily/extender-engraver.cc b/lily/extender-engraver.cc
index f44460530d..c1ca8d6a92 100644
--- a/lily/extender-engraver.cc
+++ b/lily/extender-engraver.cc
@@ -28,7 +28,7 @@ public:
   TRANSLATOR_DECLARATIONS (Extender_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(lyric_syllable);
   virtual void finalize ();
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
@@ -61,22 +61,17 @@ Extender_engraver::process_music ()
 }
 
 void
-Extender_engraver::acknowledge_grob (Grob_info i)
+Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
 {
-  Item *item = dynamic_cast<Item *> (i.grob ());
+  Item *item = i.item ();
+  if (extender_)
+    extender_->set_bound (LEFT, item);
 
-  if (item
-      && item->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
+  if (pending_extender_)
     {
-      if (extender_)
-	extender_->set_bound (LEFT, item);
-
-      if (pending_extender_)
-	{
-	  pending_extender_->set_object ("next", item->self_scm ());
-	  completize_extender (pending_extender_);
-	  pending_extender_ = 0;
-	}
+      pending_extender_->set_object ("next", item->self_scm ());
+      completize_extender (pending_extender_);
+      pending_extender_ = 0;
     }
 }
 
@@ -150,10 +145,11 @@ Extender_engraver::finalize ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Extender_engraver,lyric_syllable);
 ADD_TRANSLATOR (Extender_engraver,
 		/* descr */ "Create lyric extenders",
 		/* creats*/ "LyricExtender",
 		/* accepts */ "extender-event",
-		/* acks  */ "lyric-syllable-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/fingering-engraver.cc b/lily/fingering-engraver.cc
index 245202faa1..b024f4b7c5 100644
--- a/lily/fingering-engraver.cc
+++ b/lily/fingering-engraver.cc
@@ -25,7 +25,8 @@ protected:
   virtual bool try_music (Music *m);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
+  DECLARE_ACKNOWLEDGER(stem);
 
 private:
   void make_script (Direction, Music *, int);
@@ -43,24 +44,23 @@ Fingering_engraver::try_music (Music *m)
 }
 
 void
-Fingering_engraver::acknowledge_grob (Grob_info inf)
+Fingering_engraver::acknowledge_stem (Grob_info inf)
 {
-  if (Stem::has_interface (inf.grob ()))
+  for (int i = 0; i < fingerings_.size (); i++)
     {
-      for (int i = 0; i < fingerings_.size (); i++)
-	{
-	  Side_position_interface::add_support (fingerings_[i], inf.grob ());
-	}
+      Side_position_interface::add_support (fingerings_[i], inf.grob ());
     }
-  else if (Rhythmic_head::has_interface (inf.grob ()))
+}
+
+void
+Fingering_engraver::acknowledge_rhythmic_head (Grob_info inf)
+{
+  for (int i = 0; i < fingerings_.size (); i++)
     {
-      for (int i = 0; i < fingerings_.size (); i++)
-	{
-	  Grob *t = fingerings_[i];
-	  Side_position_interface::add_support (t, inf.grob ());
-	  if (!t->get_parent (X_AXIS))
-	    t->set_parent (inf.grob (), X_AXIS);
-	}
+      Grob *t = fingerings_[i];
+      Side_position_interface::add_support (t, inf.grob ());
+      if (!t->get_parent (X_AXIS))
+	t->set_parent (inf.grob (), X_AXIS);
     }
 }
 
@@ -139,6 +139,8 @@ Fingering_engraver::Fingering_engraver ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Fingering_engraver,rhythmic_head);
+ADD_ACKNOWLEDGER(Fingering_engraver,stem);
 ADD_TRANSLATOR (Fingering_engraver,
 		/* descr */ "Create fingering-scripts",
 		/* creats*/ "Fingering",
diff --git a/lily/font-size-engraver.cc b/lily/font-size-engraver.cc
index 762226f2c9..b91107a8a9 100644
--- a/lily/font-size-engraver.cc
+++ b/lily/font-size-engraver.cc
@@ -14,7 +14,7 @@ class Font_size_engraver : public Engraver
 
   TRANSLATOR_DECLARATIONS (Font_size_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info gi);
+  DECLARE_ACKNOWLEDGER(font);
 private:
 };
 
@@ -23,7 +23,7 @@ Font_size_engraver::Font_size_engraver ()
 }
 
 void
-Font_size_engraver::acknowledge_grob (Grob_info gi)
+Font_size_engraver::acknowledge_font (Grob_info gi)
 {
   SCM sz = get_property ("fontSize");
 
@@ -44,10 +44,11 @@ Font_size_engraver::acknowledge_grob (Grob_info gi)
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Font_size_engraver,font);
 ADD_TRANSLATOR (Font_size_engraver,
 		/* descr */ "Puts fontSize into font-relative-size grob property.",
 		/* creats*/ "",
 		/* accepts */ "",
-		/* acks  */ "font-interface",
+		/* acks  */ "",
 		/* reads */ "fontSize",
 		/* write */ "");
diff --git a/lily/glissando-engraver.cc b/lily/glissando-engraver.cc
index 0ad3384bfa..16db55ec15 100644
--- a/lily/glissando-engraver.cc
+++ b/lily/glissando-engraver.cc
@@ -21,7 +21,7 @@ public:
   TRANSLATOR_DECLARATIONS (Glissando_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual bool try_music (Music *);
@@ -59,17 +59,14 @@ Glissando_engraver::process_music ()
 }
 
 void
-Glissando_engraver::acknowledge_grob (Grob_info info)
+Glissando_engraver::acknowledge_rhythmic_head (Grob_info info)
 {
-  if (Rhythmic_head::has_interface (info.grob ()))
-    {
-      Grob *g = info.grob ();
-      if (line_)
-	line_->set_bound (LEFT, g);
+  Grob *g = info.grob ();
+  if (line_)
+    line_->set_bound (LEFT, g);
 
-      if (last_line_)
-	last_line_->set_bound (RIGHT, g);
-    }
+  if (last_line_)
+    last_line_->set_bound (RIGHT, g);
 }
 
 void
@@ -108,10 +105,11 @@ Glissando_engraver::finalize ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Glissando_engraver,rhythmic_head);
 ADD_TRANSLATOR (Glissando_engraver,
 		/* descr */ "Engrave a glissandi",
 		/* creats*/ "Glissando",
 		/* accepts */ "glissando-event",
-		/* acks  */ "rhythmic-head-interface",
+		/* acks  */ "",
 		/* reads */ "followVoice",
 		/* write */ "");
diff --git a/lily/grid-line-span-engraver.cc b/lily/grid-line-span-engraver.cc
index 9a49bdf58e..73e81736c3 100644
--- a/lily/grid-line-span-engraver.cc
+++ b/lily/grid-line-span-engraver.cc
@@ -19,7 +19,7 @@ class Grid_line_span_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Grid_line_span_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(grid_point);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
 
@@ -29,10 +29,10 @@ Grid_line_span_engraver::Grid_line_span_engraver ()
 }
 
 void
-Grid_line_span_engraver::acknowledge_grob (Grob_info i)
+Grid_line_span_engraver::acknowledge_grid_point (Grob_info i)
 {
   int depth = i.origin_contexts (this).size ();
-  if (depth && i.grob ()->internal_has_interface (ly_symbol2scm ("grid-point-interface")))
+  if (depth)
     {
       Item *it = dynamic_cast<Item *> (i.grob ());
       lines_.push (it);
@@ -59,12 +59,12 @@ Grid_line_span_engraver::stop_translation_timestep ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Grid_line_span_engraver, grid_point);
 ADD_TRANSLATOR (Grid_line_span_engraver,
 		/* descr */ "This engraver makes cross-staff linelines: It catches all normal "
 		"line lines, and draws a single span-line across them.",
 		/* creats*/ "GridLine",
 		/* accepts */ "",
-		/* acks  */ "grid-point-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/grob-info.cc b/lily/grob-info.cc
index 6b69bfeab6..161fe778e5 100644
--- a/lily/grob-info.cc
+++ b/lily/grob-info.cc
@@ -11,6 +11,8 @@
 #include "music.hh"
 #include "translator-group.hh"
 #include "context.hh"
+#include "spanner.hh"
+#include "item.hh"
 
 
 Grob_info::Grob_info (Translator *t, Grob *g)
@@ -54,3 +56,14 @@ Grob_info::context () const
   return origin_trans_->context ();
 }
 
+Spanner*
+Grob_info::spanner () const
+{
+  return dynamic_cast<Spanner*> (grob_);
+}
+
+Item*
+Grob_info::item () const
+{
+  return dynamic_cast<Item*> (grob_);
+}
diff --git a/lily/grob-pq-engraver.cc b/lily/grob-pq-engraver.cc
index 60327dc7b6..00ca948cd6 100644
--- a/lily/grob-pq-engraver.cc
+++ b/lily/grob-pq-engraver.cc
@@ -28,7 +28,7 @@ public:
   TRANSLATOR_DECLARATIONS (Grob_pq_engraver);
 protected:
   virtual void initialize ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(grob);
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 
@@ -135,12 +135,12 @@ Grob_pq_engraver::start_translation_timestep ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Grob_pq_engraver, grob);
 ADD_TRANSLATOR (Grob_pq_engraver,
 
 		/* descr */ "Administrate when certain grobs (eg. note heads) stop playing",
 		/* creats*/ "",
 		/* accepts */ "",
-		/* acks  */ "grob-interface",
+		/* acks  */ "",
 		/* reads */ "busyGrobs",
 		/* write */ "busyGrobs");
diff --git a/lily/hara-kiri-engraver.cc b/lily/hara-kiri-engraver.cc
index d6a28d4887..e73c67ab4b 100644
--- a/lily/hara-kiri-engraver.cc
+++ b/lily/hara-kiri-engraver.cc
@@ -16,7 +16,7 @@ class Hara_kiri_engraver : public Axis_group_engraver
 {
 protected:
   virtual Spanner *get_spanner ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(grob);
   virtual void add_element (Grob *e);
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
 
@@ -67,7 +67,7 @@ Hara_kiri_engraver::Hara_kiri_engraver ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Hara_kiri_engraver, grob);
 ADD_TRANSLATOR (Hara_kiri_engraver,
 		/* descr */ "Like Axis_group_engraver, but make a hara-kiri spanner, and add "
 		"interesting items (ie. note heads, lyric syllables and normal rests) ",
diff --git a/lily/horizontal-bracket-engraver.cc b/lily/horizontal-bracket-engraver.cc
index 0a4a388fb9..0148204f9c 100644
--- a/lily/horizontal-bracket-engraver.cc
+++ b/lily/horizontal-bracket-engraver.cc
@@ -24,16 +24,16 @@ public:
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
 };
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Horizontal_bracket_engraver,note_column);
 ADD_TRANSLATOR (Horizontal_bracket_engraver,
 		"Create horizontal brackets over notes for musical analysis purposes.",
 		"HorizontalBracket",
 		"note-grouping-event",
-		"note-column-interface",
+		"",
 		"",
 		"");
 
@@ -71,18 +71,15 @@ Horizontal_bracket_engraver::try_music (Music *m)
 }
 
 void
-Horizontal_bracket_engraver::acknowledge_grob (Grob_info gi)
+Horizontal_bracket_engraver::acknowledge_note_column (Grob_info gi)
 {
-  if (Note_column::has_interface (gi.grob ()))
+  for (int i = 0; i < bracket_stack_.size (); i++)
     {
-      for (int i = 0; i < bracket_stack_.size (); i++)
-	{
-	  Side_position_interface::add_support (bracket_stack_[i], gi.grob ());
-	  Pointer_group_interface::add_grob (bracket_stack_[i],
-					     ly_symbol2scm ("columns"), gi.grob ());
-	  add_bound_item (bracket_stack_[i],
-			  gi.grob ());
-	}
+      Side_position_interface::add_support (bracket_stack_[i], gi.grob ());
+      Pointer_group_interface::add_grob (bracket_stack_[i],
+					 ly_symbol2scm ("columns"), gi.grob ());
+      add_bound_item (bracket_stack_[i],
+		      gi.grob ());
     }
 }
 
diff --git a/lily/hyphen-engraver.cc b/lily/hyphen-engraver.cc
index 0e826430df..e898f03879 100644
--- a/lily/hyphen-engraver.cc
+++ b/lily/hyphen-engraver.cc
@@ -24,7 +24,7 @@ public:
   TRANSLATOR_DECLARATIONS (Hyphen_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(lyric_syllable);
   virtual void finalize ();
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
@@ -40,18 +40,14 @@ Hyphen_engraver::Hyphen_engraver ()
 }
 
 void
-Hyphen_engraver::acknowledge_grob (Grob_info i)
+Hyphen_engraver::acknowledge_lyric_syllable (Grob_info i)
 {
-  Item *item = dynamic_cast<Item *> (i.grob ());
-  // -> Text_item
-  if (item && item->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
-    {
-      if (hyphen_)
-	hyphen_->set_bound (LEFT, item);
+  Item *item = i.item();
+  if (hyphen_)
+    hyphen_->set_bound (LEFT, item);
 
-      if (finished_hyphen_)
-	finished_hyphen_->set_bound (RIGHT, item);
-    }
+  if (finished_hyphen_)
+    finished_hyphen_->set_bound (RIGHT, item);
 }
 
 bool
@@ -138,10 +134,11 @@ Hyphen_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Hyphen_engraver,lyric_syllable);
 ADD_TRANSLATOR (Hyphen_engraver,
 		/* descr */ "Create lyric hyphens",
 		/* creats*/ "LyricHyphen",
 		/* accepts */ "hyphen-event",
-		/* acks  */ "lyric-syllable-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/include/axis-group-engraver.hh b/lily/include/axis-group-engraver.hh
index 131c6663d6..a6715f82cf 100644
--- a/lily/include/axis-group-engraver.hh
+++ b/lily/include/axis-group-engraver.hh
@@ -23,7 +23,7 @@ protected:
   Link_array<Grob> elts_;
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(grob);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   virtual Spanner *get_spanner ();
   virtual void add_element (Grob *);
diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh
index 25b3d71774..680bee5105 100644
--- a/lily/include/grob-info.hh
+++ b/lily/include/grob-info.hh
@@ -19,9 +19,9 @@
 class Grob_info
 {
   Translator *origin_trans_;
-  friend class Engraver;
   Grob *grob_;
 
+  friend class Engraver;
 public:
   Grob *grob () const { return grob_; }
   Translator *origin_translator () const { return origin_trans_; } 
@@ -31,6 +31,9 @@ public:
   Link_array<Context> origin_contexts (Translator *) const;
   Grob_info (Translator *, Grob *);
   Grob_info ();
+
+  Item *item () const;
+  Spanner *spanner () const;
 };
 
 #endif // STAFFELEMINFO_HH
diff --git a/lily/include/ligature-engraver.hh b/lily/include/ligature-engraver.hh
index 11bb055d88..453083d197 100644
--- a/lily/include/ligature-engraver.hh
+++ b/lily/include/ligature-engraver.hh
@@ -33,7 +33,9 @@ protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
 
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(rest);
+  DECLARE_ACKNOWLEDGER(note_head);
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual Spanner *create_ligature_spanner (); /* abstract method */
diff --git a/lily/include/lily-proto.hh b/lily/include/lily-proto.hh
index 0270d7a751..15c990ddff 100644
--- a/lily/include/lily-proto.hh
+++ b/lily/include/lily-proto.hh
@@ -60,6 +60,7 @@ class Grace_iterator;
 class Grace_music;
 class Grob;
 class Grob_array;
+class Grob_info;
 class Hara_kiri_engraver;
 class Hara_kiri_line_group_engraver;
 class Includable_lexer;
@@ -170,4 +171,11 @@ class Transposed_music;
 class Type_swallow_translator;
 class yyFlexLexer;
 
+
+typedef void (*Engraver_void_function_engraver_grob_info)(Engraver*, Grob_info);
+typedef void (*Translator_void_method_ptr)(Translator*);
+
+
+
+
 #endif /* LILY_PROTO_HH */
diff --git a/lily/include/paper-column-engraver.hh b/lily/include/paper-column-engraver.hh
index fce678276a..dae914de8a 100644
--- a/lily/include/paper-column-engraver.hh
+++ b/lily/include/paper-column-engraver.hh
@@ -27,7 +27,10 @@ protected:
   virtual void initialize ();
   virtual void finalize ();
   virtual bool try_music (Music*);
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(item);
+  DECLARE_ACKNOWLEDGER(note_spacing);
+  DECLARE_ACKNOWLEDGER(staff_spacing);
 
   System *system_;
   Music *break_event_;
diff --git a/lily/include/staff-symbol-engraver.hh b/lily/include/staff-symbol-engraver.hh
index 7a67ca7851..bc7c0d7920 100644
--- a/lily/include/staff-symbol-engraver.hh
+++ b/lily/include/staff-symbol-engraver.hh
@@ -33,7 +33,7 @@ protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual bool try_music (Music *);
   virtual ~Staff_symbol_engraver ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(grob);
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void process_music ();
 };
diff --git a/lily/include/translator-dispatch-list.hh b/lily/include/translator-dispatch-list.hh
new file mode 100644
index 0000000000..9691dae857
--- /dev/null
+++ b/lily/include/translator-dispatch-list.hh
@@ -0,0 +1,35 @@
+/*
+  translator-dispatch-list.hh -- declare Translator_dispatch_list
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef TRANSLATOR_DISPATCH_LIST_HH
+#define TRANSLATOR_DISPATCH_LIST_HH
+
+#include "lily-proto.hh"
+#include "lily-guile.hh"
+#include "array.hh"
+#include "smobs.hh"
+
+struct Engraver_dispatch_entry
+{
+  Engraver *engraver_;
+  Engraver_void_function_engraver_grob_info function_;
+};
+
+class Engraver_dispatch_list
+{
+  Array<Engraver_dispatch_entry> dispatch_entries_;
+public:
+  void apply (Grob_info);
+  SCM static create (SCM trans_list,
+		     SCM iface_list);
+
+  DECLARE_SIMPLE_SMOBS(Engraver_dispatch_list,);
+};
+
+#endif /* TRANSLATOR_DISPATCH_LIST_HH */
diff --git a/lily/include/translator.hh b/lily/include/translator.hh
index d938f52aa8..4056c8d5da 100644
--- a/lily/include/translator.hh
+++ b/lily/include/translator.hh
@@ -16,18 +16,12 @@
 #include "input.hh"
 #include "smobs.hh"
 
-
-
-typedef void (*Translator_void_method_ptr)(Translator*);
-
-
 struct Acknowledge_information
 {
   SCM symbol_;
-  Translator_void_method_ptr function_;
+  Engraver_void_function_engraver_grob_info function_;
 };
 
-
 #define TRANSLATOR_DECLARATIONS(NAME)			\
   public:						\
   NAME ();						\
@@ -37,10 +31,12 @@ struct Acknowledge_information
   virtual void fetch_precomputable_methods (Translator_void_method_ptr methods[]);\
   virtual SCM static_translator_description () const;	\
   virtual SCM translator_description () const; \
-  virtual Translator_void_method_ptr get_acknowledger (SCM sym) { \
+  virtual Engraver_void_function_engraver_grob_info get_acknowledger (SCM sym) { \
     return static_get_acknowledger (sym);\
   }\
-  static Translator_void_method_ptr static_get_acknowledger (SCM sym);
+  static Engraver_void_function_engraver_grob_info static_get_acknowledger (SCM sym);
+
+#define DECLARE_ACKNOWLEDGER(x) public: void acknowledge_ ## x (Grob_info); protected:
 
 enum Translator_precompute_index {
   START_TRANSLATION_TIMESTEP,
diff --git a/lily/include/translator.icc b/lily/include/translator.icc
index b90b1fd753..3097972a4c 100644
--- a/lily/include/translator.icc
+++ b/lily/include/translator.icc
@@ -34,7 +34,7 @@
   Array<Acknowledge_information> classname::acknowledge_static_array_;\
   IMPLEMENT_FETCH_PRECOMPUTABLE_METHODS(classname); \
   ADD_THIS_TRANSLATOR (classname);					\
-  Translator_void_method_ptr\
+  Engraver_void_function_engraver_grob_info\
   classname::static_get_acknowledger (SCM sym)				\
   {\
     return generic_get_acknowledger (sym, &acknowledge_static_array_);\
@@ -92,16 +92,21 @@ T::fetch_precomputable_methods (Translator_void_method_ptr ptrs[])\
     : (Translator_void_method_ptr) &T::process_acknowledged;		\
 }
 
-void add_acknowledger (Translator_void_method_ptr ptr, const char *func_name, Array<Acknowledge_information> *ack_array);
-Translator_void_method_ptr
-generic_get_acknowledger (SCM sym, Array<Acknowledge_information> const *ack_array);
+void add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
+		       const char *func_name,
+		       Array<Acknowledge_information> *ack_array);
+
+Engraver_void_function_engraver_grob_info
+generic_get_acknowledger (SCM sym,
+			  Array<Acknowledge_information> const *ack_array);
 
 #define ADD_ACKNOWLEDGER(CLASS,NAME)		\
 void CLASS ## NAME ## _ack_adder () \
 {\
-  add_acknowledger ((Translator_void_method_ptr) &CLASS::NAME, #NAME, &CLASS::acknowledge_static_array_);\
+  add_acknowledger ((Engraver_void_function_engraver_grob_info) &CLASS::acknowledge_ ## NAME, #NAME, &CLASS::acknowledge_static_array_);\
 }\
-ADD_SCM_INIT_FUNC(CLASS ## NAME ## _ack_adder);\
+  ADD_SCM_INIT_FUNC(CLASS ## NAME ## _ack_adder_initclass, CLASS ## NAME ## _ack_adder); \
+
 
 
 
diff --git a/lily/instrument-name-engraver.cc b/lily/instrument-name-engraver.cc
index f1182ea8b6..bf935c31a7 100644
--- a/lily/instrument-name-engraver.cc
+++ b/lily/instrument-name-engraver.cc
@@ -16,6 +16,8 @@
 #include "text-interface.hh"
 #include "grob-array.hh"
 
+#include "translator.icc"
+
 class Instrument_name_engraver : public Engraver
 {
   bool first_; 
@@ -27,7 +29,10 @@ protected:
 
   virtual void create_text ();
   virtual void initialize ();
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(bar_line);
+  DECLARE_ACKNOWLEDGER(axis_group);
+  
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
   
@@ -81,13 +86,16 @@ Instrument_name_engraver::create_text ()
 }
 
 void
-Instrument_name_engraver::acknowledge_grob (Grob_info i)
+Instrument_name_engraver::acknowledge_bar_line (Grob_info i)
 {
-  if (Bar_line::has_interface (i.grob ()))
-    {
-      create_text ();
-    }
+  (void)i;
+  create_text ();
+}
 
+
+void
+Instrument_name_engraver::acknowledge_axis_group (Grob_info i)
+{
   /*
     Ugh - typechecking for pedal and dynamic sucks.
   */
@@ -131,6 +139,9 @@ Instrument_name_engraver::process_music ()
 
 #include "translator.icc"
 
+
+ADD_ACKNOWLEDGER(Instrument_name_engraver, bar_line);
+ADD_ACKNOWLEDGER(Instrument_name_engraver, axis_group);
 ADD_TRANSLATOR (Instrument_name_engraver,
 		/* descr */ " Prints the name of the instrument (specified by "
 		" @code{Staff.instrument} and @code{Staff.instr}) "
@@ -177,14 +188,14 @@ Vocal_name_engraver::create_text ()
     text_->set_property ("text", txt);
 }
 
-#include "translator.icc"
-
+ADD_ACKNOWLEDGER(Vocal_name_engraver, bar_line);
+ADD_ACKNOWLEDGER(Vocal_name_engraver, axis_group);
 ADD_TRANSLATOR (Vocal_name_engraver,
 		/* descr */ " Prints the name of the a lyric voice (specified by "
 		" @code{Staff.vocalName} and @code{Staff.vocNam}) "
 		"at the left of the staff. ",
 		/* creats*/ "VocalName",
 		/* accepts */ "",
-		/* acks  */ "bar-line-interface axis-group-interface",
+		/* acks  */ "",
 		/* reads */ "vocNam vocalName",
 		/* write */ "");
diff --git a/lily/key-engraver.cc b/lily/key-engraver.cc
index c1a973f4a0..cd813ea00b 100644
--- a/lily/key-engraver.cc
+++ b/lily/key-engraver.cc
@@ -39,7 +39,10 @@ protected:
   virtual bool try_music (Music *ev);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(clef);
+  DECLARE_ACKNOWLEDGER(bar_line);
+  
 };
 
 void
@@ -102,18 +105,19 @@ Key_engraver::try_music (Music *ev)
 }
 
 void
-Key_engraver::acknowledge_grob (Grob_info info)
+Key_engraver::acknowledge_clef (Grob_info info)
 {
-  if (Clef::has_interface (info.grob ()))
+  SCM c = get_property ("createKeyOnClefChange");
+  if (to_boolean (c))
     {
-      SCM c = get_property ("createKeyOnClefChange");
-      if (to_boolean (c))
-	{
-	  create_key (false);
-	}
+      create_key (false);
     }
-  else if (Bar_line::has_interface (info.grob ())
-	   && scm_is_pair (get_property ("keySignature")))
+}
+
+void
+Key_engraver::acknowledge_bar_line (Grob_info info)
+{
+  if (scm_is_pair (get_property ("keySignature")))
     {
       create_key (true);
     }
@@ -176,10 +180,12 @@ Key_engraver::initialize ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Key_engraver,clef);
+ADD_ACKNOWLEDGER(Key_engraver,bar_line);
 ADD_TRANSLATOR (Key_engraver,
 		/* descr */ "",
 		/* creats*/ "KeySignature",
 		/* accepts */ "key-change-event",
-		/* acks  */ "bar-line-interface clef-interface",
+		/* acks  */ "",
 		/* reads */ "keySignature printKeyCancellation lastKeySignature explicitKeySignatureVisibility createKeyOnClefChange keyAccidentalOrder keySignature",
 		/* write */ "lastKeySignature tonic keySignature");
diff --git a/lily/ledger-line-engraver.cc b/lily/ledger-line-engraver.cc
index 32568dd309..cd86fde310 100644
--- a/lily/ledger-line-engraver.cc
+++ b/lily/ledger-line-engraver.cc
@@ -21,7 +21,9 @@ public:
 protected:
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+ 
+  DECLARE_ACKNOWLEDGER(ledgered);
+  DECLARE_ACKNOWLEDGER(staff_symbol);
 
   void start_spanner ();
   void stop_spanner ();
@@ -65,20 +67,22 @@ Ledger_line_engraver::stop_spanner ()
 }
 
 void
-Ledger_line_engraver::acknowledge_grob (Grob_info s)
+Ledger_line_engraver::acknowledge_staff_symbol (Grob_info s)
 {
-  if (Staff_symbol::has_interface (s.grob ()))
+  Spanner *sym = dynamic_cast<Spanner*> (s.grob ());
+
+  if (!span_
+      || span_->get_bound (LEFT) != sym->get_bound (LEFT))
     {
-      Spanner *sym = dynamic_cast<Spanner*> (s.grob ());
-
-      if (!span_
-	  || span_->get_bound (LEFT) != sym->get_bound (LEFT))
-	{
-	  stop_spanner ();
-	  start_spanner ();
-	}
+      stop_spanner ();
+      start_spanner ();
     }
-  else if (span_)
+}
+
+void
+Ledger_line_engraver::acknowledge_ledgered (Grob_info s)
+{
+  if (span_)
     {
       if (!to_boolean (s.grob ()->get_property ("no-ledgers")))
 	Pointer_group_interface::add_grob (span_, ly_symbol2scm ("note-heads"),
@@ -88,10 +92,12 @@ Ledger_line_engraver::acknowledge_grob (Grob_info s)
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Ledger_line_engraver,ledgered);
+ADD_ACKNOWLEDGER(Ledger_line_engraver,staff_symbol);
 ADD_TRANSLATOR (Ledger_line_engraver,
 		"Creates the spanner to draw ledger lines, and notices objects that need ledger lines",
 		/* creats*/ "LedgerLineSpanner",
 		/* accepts */ "",
-		/* acks  */ "staff-symbol-interface ledgered-interface", // ledgered-interface? 
+		/* acks  */ "", // ledgered-interface? 
 		/* reads */ "",
 		/* write */ "")
diff --git a/lily/ligature-bracket-engraver.cc b/lily/ligature-bracket-engraver.cc
index 175f8d1269..9d00279b1c 100644
--- a/lily/ligature-bracket-engraver.cc
+++ b/lily/ligature-bracket-engraver.cc
@@ -21,7 +21,8 @@ class Ligature_bracket_engraver : public Ligature_engraver
 {
 protected:
   virtual Spanner *create_ligature_spanner ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rest);
+  DECLARE_ACKNOWLEDGER(note_column);
 public:
   TRANSLATOR_DECLARATIONS (Ligature_bracket_engraver);
 };
@@ -37,25 +38,30 @@ Ligature_bracket_engraver::create_ligature_spanner ()
 }
 
 void
-Ligature_bracket_engraver::acknowledge_grob (Grob_info info)
+Ligature_bracket_engraver::acknowledge_note_column (Grob_info info)
 {
   if (current_ligature ())
     {
-      if (Note_column::has_interface (info.grob ()))
-	{
-	  Tuplet_bracket::add_column (current_ligature (),
-				      dynamic_cast<Item *> (info.grob ()));
-	}
-      else Ligature_engraver::acknowledge_grob (info);
+      Tuplet_bracket::add_column (current_ligature (),
+				  dynamic_cast<Item *> (info.grob ()));
     }
 }
 
+void
+Ligature_bracket_engraver::acknowledge_rest (Grob_info info)
+{
+  if (current_ligature ())
+    Ligature_engraver::acknowledge_rest (info);
+}
+
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Ligature_bracket_engraver, rest);
+ADD_ACKNOWLEDGER(Ligature_bracket_engraver, note_column);
 ADD_TRANSLATOR (Ligature_bracket_engraver,
 		/* descr */ "Handles Ligature_events by engraving Ligature brackets.",
 		/* creats*/ "TupletBracket",
 		/* accepts */ "ligature-event",
-		/* acks  */ "rest-interface note-column-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/ligature-engraver.cc b/lily/ligature-engraver.cc
index fe680c7a7d..7f47ce5165 100644
--- a/lily/ligature-engraver.cc
+++ b/lily/ligature-engraver.cc
@@ -265,32 +265,34 @@ Ligature_engraver::current_ligature ()
 }
 
 void
-Ligature_engraver::acknowledge_grob (Grob_info info)
+Ligature_engraver::acknowledge_note_head (Grob_info info)
 {
   if (ligature_)
     {
-      if (Note_head::has_interface (info.grob ()))
-	{
-	  primitives_.push (info);
-	  info.grob ()->set_property ("print-function",
-				    brew_ligature_primitive_proc);
-	}
-      if (Rest::has_interface (info.grob ()))
-	{
-	  info.music_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest"));
-	  prev_start_event_->origin ()->warning (_ ("ligature was started here"));
-	  // TODO: maybe better should stop ligature here rather than
-	  // ignoring the rest?
-	}
+      primitives_.push (info);
+      info.grob ()->set_property ("print-function",
+				  brew_ligature_primitive_proc);
     }
 }
 
+void
+Ligature_engraver::acknowledge_rest (Grob_info info)
+{
+  info.music_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest"));
+  prev_start_event_->origin ()->warning (_ ("ligature was started here"));
+  // TODO: maybe better should stop ligature here rather than
+  // ignoring the rest?
+}
+
+
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Ligature_engraver, rest);
+ADD_ACKNOWLEDGER(Ligature_engraver, note_head);
 ADD_TRANSLATOR (Ligature_engraver,
 		/* descr */ "Abstract class; a concrete subclass handles Ligature_events by engraving Ligatures in a concrete style.",
 		/* creats */ "",
 		/* accepts */ "ligature-event",
-		/* acks  */ "note-head-interface rest-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/mark-engraver.cc b/lily/mark-engraver.cc
index d938b39004..d88f745277 100644
--- a/lily/mark-engraver.cc
+++ b/lily/mark-engraver.cc
@@ -27,7 +27,7 @@ protected:
   Item *text_;
 protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(bar_line);
   void create_items (Music *);
   virtual bool try_music (Music *ev);
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -43,10 +43,10 @@ Mark_engraver::Mark_engraver ()
 }
 
 void
-Mark_engraver::acknowledge_grob (Grob_info inf)
+Mark_engraver::acknowledge_bar_line (Grob_info inf)
 {
   Grob *s = inf.grob ();
-  if (text_ && Bar_line::has_interface (s))
+  if (text_)
     {
       /*
 	TODO: make this configurable. RehearsalMark cannot be
@@ -132,6 +132,7 @@ Mark_engraver::process_music ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Mark_engraver,bar_line);
 ADD_TRANSLATOR (Mark_engraver,
 		/* descr */ "This engraver will create RehearsalMark objects. "
 		"It puts them on top of all staves (which is taken from "
@@ -141,6 +142,6 @@ ADD_TRANSLATOR (Mark_engraver,
 		"end up on the same Y-location",
 		/* creats*/ "RehearsalMark",
 		/* accepts */ "mark-event",
-		/* acks  */ "bar-line-interface",
+		/* acks  */ "",
 		/* reads */ "rehearsalMark markFormatter stavesFound",
 		/* write */ "");
diff --git a/lily/measure-grouping-engraver.cc b/lily/measure-grouping-engraver.cc
index 7a7ebd635d..6484f98df5 100644
--- a/lily/measure-grouping-engraver.cc
+++ b/lily/measure-grouping-engraver.cc
@@ -11,6 +11,8 @@
 #include "global-context.hh"
 #include "engraver.hh"
 
+#include "translator.icc"
+
 class Measure_grouping_engraver : public Engraver
 {
 public:
@@ -22,7 +24,7 @@ protected:
 
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
 };
 
 void
@@ -37,7 +39,7 @@ Measure_grouping_engraver::finalize ()
 }
 
 void
-Measure_grouping_engraver::acknowledge_grob (Grob_info gi)
+Measure_grouping_engraver::acknowledge_note_column (Grob_info gi)
 {
   if (grouping_)
     {
@@ -104,12 +106,11 @@ Measure_grouping_engraver::Measure_grouping_engraver ()
   grouping_ = 0;
 }
 
-#include "translator.icc"
-
+ADD_ACKNOWLEDGER(Measure_grouping_engraver, note_column);
 ADD_TRANSLATOR (Measure_grouping_engraver,
 		/* descr */ "Creates MeasureGrouping to indicate beat subdivision.",
 		/* creats*/ "MeasureGrouping",
 		/* accepts */ "",
-		/* acks  */ "note-column-interface",
+		/* acks  */ "",
 		/* reads */ "beatGrouping beatLength measurePosition currentMusicalColumn",
 		/* write */ "");
diff --git a/lily/moment.cc b/lily/moment.cc
index 8b866922a8..a8d23fa428 100644
--- a/lily/moment.cc
+++ b/lily/moment.cc
@@ -33,6 +33,7 @@ Moment::Moment (Rational m)
 }
 
 #include "ly-smobs.icc"
+
 IMPLEMENT_SIMPLE_SMOBS (Moment);
 IMPLEMENT_TYPE_P (Moment, "ly:moment?");
 
diff --git a/lily/new-fingering-engraver.cc b/lily/new-fingering-engraver.cc
index 6bed794981..f39a35f5c2 100644
--- a/lily/new-fingering-engraver.cc
+++ b/lily/new-fingering-engraver.cc
@@ -15,6 +15,8 @@
 #include "script-interface.hh"
 #include "stem.hh"
 
+#include "translator.icc"
+
 struct Finger_tuple
 {
   Grob *head_;
@@ -50,7 +52,8 @@ public:
   TRANSLATOR_DECLARATIONS (New_fingering_engraver);
 protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
+  DECLARE_ACKNOWLEDGER(stem);
   void add_fingering (Grob *, Music *, Music *);
   void add_script (Grob *, Music *, Music *);
   void add_string (Grob *, Music *, Music *);
@@ -58,54 +61,53 @@ protected:
 };
 
 void
-New_fingering_engraver::acknowledge_grob (Grob_info inf)
+New_fingering_engraver::acknowledge_rhythmic_head (Grob_info inf)
 {
-  if (Rhythmic_head::has_interface (inf.grob ()))
+  Music *note_ev = inf.music_cause ();
+  if (!note_ev)
+    return;
+
+  SCM arts = note_ev->get_property ("articulations");
+
+  for (SCM s = arts; scm_is_pair (s); s = scm_cdr (s))
     {
-      Music *note_ev = inf.music_cause ();
-      if (!note_ev)
-	return;
+      Music *m = unsmob_music (scm_car (s));
 
-      SCM arts = note_ev->get_property ("articulations");
+      if (!m)
+	continue;
 
-      for (SCM s = arts; scm_is_pair (s); s = scm_cdr (s))
+      if (m->is_mus_type ("fingering-event"))
 	{
-	  Music *m = unsmob_music (scm_car (s));
-
-	  if (!m)
-	    continue;
-
-	  if (m->is_mus_type ("fingering-event"))
-	    {
-	      add_fingering (inf.grob (), m, note_ev);
-	    }
-	  else if (m->is_mus_type ("text-script-event"))
-	    {
-	      m->origin ()->warning (_ ("can't add text scripts to individual note heads"));
-	    }
-	  else if (m->is_mus_type ("script-event"))
-	    {
-	      add_script (inf.grob (), m, note_ev);
-	    }
-	  else if (m->is_mus_type ("string-number-event"))
-	    {
-	      add_string (inf.grob (), m, note_ev);
-	    }
-	  else if (m->is_mus_type ("harmonic-event"))
-	    {
-	      inf.grob ()->set_property ("style", ly_symbol2scm ("harmonic"));
-	      Grob *d = unsmob_grob (inf.grob ()->get_object ("dot"));
-	      if (d)
-		d->suicide ();
-	    }
+	  add_fingering (inf.grob (), m, note_ev);
+	}
+      else if (m->is_mus_type ("text-script-event"))
+	{
+	  m->origin ()->warning (_ ("can't add text scripts to individual note heads"));
+	}
+      else if (m->is_mus_type ("script-event"))
+	{
+	  add_script (inf.grob (), m, note_ev);
+	}
+      else if (m->is_mus_type ("string-number-event"))
+	{
+	  add_string (inf.grob (), m, note_ev);
+	}
+      else if (m->is_mus_type ("harmonic-event"))
+	{
+	  inf.grob ()->set_property ("style", ly_symbol2scm ("harmonic"));
+	  Grob *d = unsmob_grob (inf.grob ()->get_object ("dot"));
+	  if (d)
+	    d->suicide ();
 	}
-
-      heads_.push (inf.grob ());
-    }
-  else if (Stem::has_interface (inf.grob ()))
-    {
-      stem_ = inf.grob ();
     }
+
+  heads_.push (inf.grob ());
+}
+
+void
+New_fingering_engraver::acknowledge_stem (Grob_info inf)
+{
+  stem_ = inf.grob ();
 }
 
 void
@@ -359,8 +361,8 @@ New_fingering_engraver::New_fingering_engraver ()
 {
   stem_ = 0;
 }
-
-#include "translator.icc"
+ADD_ACKNOWLEDGER(New_fingering_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER(New_fingering_engraver, stem);
 
 ADD_TRANSLATOR (New_fingering_engraver,
 		/* descr */ "Create fingering-scripts for notes in a new chord.  "
diff --git a/lily/note-head-line-engraver.cc b/lily/note-head-line-engraver.cc
index 8dde1e8640..610c480359 100644
--- a/lily/note-head-line-engraver.cc
+++ b/lily/note-head-line-engraver.cc
@@ -26,7 +26,7 @@ public:
   TRANSLATOR_DECLARATIONS (Note_head_line_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 
@@ -48,24 +48,21 @@ Note_head_line_engraver::Note_head_line_engraver ()
 }
 
 void
-Note_head_line_engraver::acknowledge_grob (Grob_info info)
+Note_head_line_engraver::acknowledge_rhythmic_head (Grob_info info)
 {
-  if (Rhythmic_head::has_interface (info.grob ()))
+  head_ = info.grob ();
+  if (to_boolean (get_property ("followVoice")))
     {
-      head_ = info.grob ();
-      if (to_boolean (get_property ("followVoice")))
+      Context *tr = context ();
+      while (tr && !tr->is_alias (ly_symbol2scm ("Staff")))
+	tr = tr->get_parent_context ();
+
+      if (tr
+	  && tr->is_alias (ly_symbol2scm ("Staff")) && tr != last_staff_)
 	{
-	  Context *tr = context ();
-	  while (tr && !tr->is_alias (ly_symbol2scm ("Staff")))
-	    tr = tr->get_parent_context ();
-
-	  if (tr
-	      && tr->is_alias (ly_symbol2scm ("Staff")) && tr != last_staff_)
-	    {
-	      if (last_head_)
-		follow_ = true;
-	      last_staff_ = tr;
-	    }
+	  if (last_head_)
+	    follow_ = true;
+	  last_staff_ = tr;
 	}
     }
 }
@@ -100,12 +97,12 @@ Note_head_line_engraver::stop_translation_timestep ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Note_head_line_engraver, rhythmic_head);
 ADD_TRANSLATOR (Note_head_line_engraver,
 		/* descr */ "Engrave a line between two note heads, for example a glissando.  If "
 		" followVoice is set, staff switches also generate a line.",
 		/* creats*/ "Glissando VoiceFollower",
 		/* accepts */ "glissando-event",
-		/* acks  */ "rhythmic-head-interface",
+		/* acks  */ "",
 		/* reads */ "followVoice",
 		/* write */ "");
diff --git a/lily/ottava-engraver.cc b/lily/ottava-engraver.cc
index 44f3741c37..dd6ee2456b 100644
--- a/lily/ottava-engraver.cc
+++ b/lily/ottava-engraver.cc
@@ -17,7 +17,9 @@ public:
   TRANSLATOR_DECLARATIONS (Ottava_spanner_engraver);
 protected:
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
+ 
+  DECLARE_ACKNOWLEDGER(note_column);
+  
   PRECOMPUTED_VIRTUAL void process_music ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void derived_mark () const;
@@ -66,10 +68,10 @@ Ottava_spanner_engraver::process_music ()
 }
 
 void
-Ottava_spanner_engraver::acknowledge_grob (Grob_info info)
+Ottava_spanner_engraver::acknowledge_note_column (Grob_info info)
 {
-  Item *it = dynamic_cast<Item *> (info.grob ());
-  if (span_ && it && Note_column::has_interface (info.grob ()))
+  Item *it = info.item();
+  if (span_ && it)
     {
       Side_position_interface::add_support (span_, it);
 
@@ -122,11 +124,11 @@ Ottava_spanner_engraver::finalize ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Ottava_spanner_engraver, note_column);
 ADD_TRANSLATOR (Ottava_spanner_engraver,
 		/* descr */ "Create a text spanner when the ottavation property changes..",
 		/* creats*/ "OttavaBracket",
 		/* accepts */ "",
-		/* acks  */ "note-column-interface",
+		/* acks  */ "",
 		/* reads */ "ottavation",
 		/* write */ "");
diff --git a/lily/output-property-engraver.cc b/lily/output-property-engraver.cc
index f31cd652fc..96f1c04a5f 100644
--- a/lily/output-property-engraver.cc
+++ b/lily/output-property-engraver.cc
@@ -13,12 +13,12 @@
 
 class Output_property_engraver : public Engraver
 {
-TRANSLATOR_DECLARATIONS (Output_property_engraver);
+  TRANSLATOR_DECLARATIONS (Output_property_engraver);
 protected:
   Link_array<Music> props_;
+  DECLARE_ACKNOWLEDGER(grob)
 
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
   virtual bool try_music (Music*);
 };
 
@@ -42,8 +42,6 @@ Output_property_engraver::acknowledge_grob (Grob_info inf)
       Music * o = props_[i];
       SCM pred = o->get_property ("predicate");
 
-
-
       if (ly_is_procedure (pred))
 	{
 	  /*
@@ -80,12 +78,12 @@ Output_property_engraver::Output_property_engraver ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Output_property_engraver,grob)
 ADD_TRANSLATOR (Output_property_engraver,
 /* descr */       "Interpret Music of Output_property type, and apply a function "
 " to any Graphic objects that satisfies the predicate.",
 /* creats*/       "",
 /* accepts */     "layout-instruction",
-/* acks  */       "grob-interface",
+/* acks  */       "",
 /* reads */       "",
 /* write */       "");
diff --git a/lily/paper-column-engraver.cc b/lily/paper-column-engraver.cc
index e61ac2d4a8..40deecd62d 100644
--- a/lily/paper-column-engraver.cc
+++ b/lily/paper-column-engraver.cc
@@ -73,29 +73,24 @@ Paper_column_engraver::initialize ()
 }
 
 void
-Paper_column_engraver::acknowledge_grob (Grob_info gi)
+Paper_column_engraver::acknowledge_item (Grob_info gi)
 {
-  Item *item = dynamic_cast<Item *> (gi.grob ());
-  if (!item)
-    {
-      programming_error ("Spanner found in Paper_column_engraver::acknowledge_grob()"); 
-      return;
-    }
-  
-  items_.push (item);
-  
-  if (Staff_spacing::has_interface (item))
-    {
-      Pointer_group_interface::add_grob (command_column_,
-					 ly_symbol2scm ("spacing-wishes"),
-					 gi.grob ());
-    }
-  if (Note_spacing::has_interface (item))
-    {
-      Pointer_group_interface::add_grob (musical_column_,
-					 ly_symbol2scm ("spacing-wishes"),
-					 gi.grob ());
-    }
+  items_.push (gi.item ());
+}
+
+void
+Paper_column_engraver::acknowledge_staff_spacing (Grob_info gi)
+{
+  Pointer_group_interface::add_grob (command_column_,
+				     ly_symbol2scm ("spacing-wishes"),
+				     gi.grob ());
+}
+void
+Paper_column_engraver::acknowledge_note_spacing (Grob_info gi)
+{
+  Pointer_group_interface::add_grob (musical_column_,
+				     ly_symbol2scm ("spacing-wishes"),
+				     gi.grob ());
 }
 
 void
@@ -217,7 +212,9 @@ Paper_column_engraver::start_translation_timestep ()
     make_columns ();
 }
 
-
+ADD_ACKNOWLEDGER(Paper_column_engraver,item);
+ADD_ACKNOWLEDGER(Paper_column_engraver,note_spacing);
+ADD_ACKNOWLEDGER(Paper_column_engraver,staff_spacing);
 
 
 ADD_TRANSLATOR (Paper_column_engraver,
@@ -231,6 +228,6 @@ ADD_TRANSLATOR (Paper_column_engraver,
 		"that there are no beams or notes that prevent a breakpoint.) ",
 		/* creats*/ "PaperColumn NonMusicalPaperColumn",
 		/* accepts */ "break-event",
-		/* acks  */ "item-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "currentCommandColumn currentMusicalColumn");
diff --git a/lily/part-combine-engraver.cc b/lily/part-combine-engraver.cc
index 6e4d63d12d..cfda8df12e 100644
--- a/lily/part-combine-engraver.cc
+++ b/lily/part-combine-engraver.cc
@@ -20,7 +20,9 @@ class Part_combine_engraver : public Engraver
   TRANSLATOR_DECLARATIONS (Part_combine_engraver);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_head);
+  DECLARE_ACKNOWLEDGER(stem);
+  
   PRECOMPUTED_VIRTUAL void process_music ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual bool try_music (Music *);
@@ -66,25 +68,25 @@ Part_combine_engraver::process_music ()
 }
 
 void
-Part_combine_engraver::acknowledge_grob (Grob_info i)
+Part_combine_engraver::acknowledge_note_head (Grob_info i)
 {
   if (text_)
     {
-      if (Note_head::has_interface (i.grob ()))
-	{
-	  Grob *t = text_;
-	  Side_position_interface::add_support (t, i.grob ());
-	  if (Side_position_interface::get_axis (t) == X_AXIS
-	      && !t->get_parent (Y_AXIS))
-	    t->set_parent (i.grob (), Y_AXIS);
-	}
-      if (Stem::has_interface (i.grob ()))
-	{
-	  Side_position_interface::add_support (text_, i.grob ());
-	}
+      Grob *t = text_;
+      Side_position_interface::add_support (t, i.grob ());
+      if (Side_position_interface::get_axis (t) == X_AXIS
+	  && !t->get_parent (Y_AXIS))
+	t->set_parent (i.grob (), Y_AXIS);
     }
 }
 
+void
+Part_combine_engraver::acknowledge_stem (Grob_info i)
+{
+  if (text_)
+      Side_position_interface::add_support (text_, i.grob ());
+}
+
 void
 Part_combine_engraver::stop_translation_timestep ()
 {
@@ -93,14 +95,14 @@ Part_combine_engraver::stop_translation_timestep ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Part_combine_engraver, note_head);
+ADD_ACKNOWLEDGER(Part_combine_engraver, stem);
 ADD_TRANSLATOR (Part_combine_engraver,
 		/* descr */ "Part combine engraver for orchestral scores:		"
 		"Print markings a2, Solo, Solo II, and unisono ",
 		/* creats*/ "CombineTextScript",
 		/* accepts */ "part-combine-event",
-		/* acks  */ "multi-measure-rest-interface "
-		"slur-interface stem-interface note-head-interface",
+		/* acks  */ "",
 		/* reads */ "printPartCombineTexts soloText soloIIText "
 		"aDueText",
 		/* write */ "");
diff --git a/lily/phrasing-slur-engraver.cc b/lily/phrasing-slur-engraver.cc
index 333cba4e7b..d2f43ca8e7 100644
--- a/lily/phrasing-slur-engraver.cc
+++ b/lily/phrasing-slur-engraver.cc
@@ -27,7 +27,16 @@ class Phrasing_slur_engraver : public Engraver
 
 protected:
   virtual bool try_music (Music *);
-  virtual void acknowledge_grob (Grob_info);
+
+  void acknowledge_extra_object (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
+  DECLARE_ACKNOWLEDGER(accidental);
+  DECLARE_ACKNOWLEDGER(fingering);
+  DECLARE_ACKNOWLEDGER(script);
+  DECLARE_ACKNOWLEDGER(tie);
+  DECLARE_ACKNOWLEDGER(text_script);
+  DECLARE_ACKNOWLEDGER(slur);
+  
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -68,46 +77,80 @@ Phrasing_slur_engraver::try_music (Music *m)
 }
 
 void
-Phrasing_slur_engraver::acknowledge_grob (Grob_info info)
+Phrasing_slur_engraver::acknowledge_note_column (Grob_info info)
 {
   Grob *e = info.grob ();
-  if (Note_column::has_interface (info.grob ()))
+  for (int i = slurs_.size (); i--;)
+    Slur::add_column (slurs_[i], e);
+  for (int i = end_slurs_.size (); i--;)
+    Slur::add_column (end_slurs_[i], e);
+}
+
+void
+Phrasing_slur_engraver::acknowledge_extra_object (Grob_info info)
+{
+  Grob*e = info.grob ();
+  SCM inside = e->get_property ("inside-slur");
+  if (Tie::has_interface (e)
+      || to_boolean (inside))
     {
       for (int i = slurs_.size (); i--;)
-	Slur::add_column (slurs_[i], e);
+	Slur::add_extra_encompass (slurs_[i], e);
       for (int i = end_slurs_.size (); i--;)
-	Slur::add_column (end_slurs_[i], e);
+	Slur::add_extra_encompass (end_slurs_[i], e);
     }
-  else
+  else if (inside == SCM_BOOL_F)
     {
-      /*
-	ugh. cut & paste from slur-engraver.cc
-      */
-      SCM inside = e->get_property ("inside-slur");
-      if (Tie::has_interface (e)
-	  || Slur::has_interface (e)
-	  || to_boolean (inside))
-	{
-	  for (int i = slurs_.size (); i--;)
-	    Slur::add_extra_encompass (slurs_[i], e);
-	  for (int i = end_slurs_.size (); i--;)
-	    Slur::add_extra_encompass (end_slurs_[i], e);
-	}
-      else if (inside == SCM_BOOL_F)
+      Grob *slur = slurs_.size () ? slurs_[0] : 0;
+      slur = (end_slurs_.size () && !slur)
+	? end_slurs_[0] : slur;
+
+      if (slur)
 	{
-	  Grob *slur = slurs_.size () ? slurs_[0] : 0;
-	  slur = (end_slurs_.size () && !slur)
-	    ? end_slurs_[0] : slur;
-
-	  if (slur)
-	    {
-	      e->add_offset_callback (Slur::outside_slur_callback_proc, Y_AXIS);
-	      e->set_object ("slur", slur->self_scm ());
-	    }
+	  e->add_offset_callback (Slur::outside_slur_callback_proc, Y_AXIS);
+	  e->set_object ("slur", slur->self_scm ());
 	}
     }
 }
 
+void
+Phrasing_slur_engraver::acknowledge_accidental (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+
+void
+Phrasing_slur_engraver::acknowledge_fingering (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Phrasing_slur_engraver::acknowledge_script (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Phrasing_slur_engraver::acknowledge_text_script (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Phrasing_slur_engraver::acknowledge_tie (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+
+void
+Phrasing_slur_engraver::acknowledge_slur (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
 void
 Phrasing_slur_engraver::finalize ()
 {
@@ -146,10 +189,19 @@ Phrasing_slur_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,note_column);
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,accidental);
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,fingering)
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,script);
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,tie);
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,text_script);
+ADD_ACKNOWLEDGER(Phrasing_slur_engraver,slur);
+
 ADD_TRANSLATOR (Phrasing_slur_engraver,
 		/* descr */ "Print phrasing slurs. Similar to @ref{Slur_engraver}",
 		/* creats*/ "PhrasingSlur",
 		/* accepts */ "phrasing-slur-event",
-		/* acks  */ "note-column-interface tie-interface fingering-interface script-interface slur-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/piano-pedal-engraver.cc b/lily/piano-pedal-engraver.cc
index 9f586a44ac..270033f29e 100644
--- a/lily/piano-pedal-engraver.cc
+++ b/lily/piano-pedal-engraver.cc
@@ -65,7 +65,7 @@ protected:
   virtual void finalize ();
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
   PRECOMPUTED_VIRTUAL void process_music ();
 
 private:
@@ -127,22 +127,19 @@ Piano_pedal_engraver::~Piano_pedal_engraver ()
   I'm a script
 */
 void
-Piano_pedal_engraver::acknowledge_grob (Grob_info info)
+Piano_pedal_engraver::acknowledge_note_column (Grob_info info)
 {
   for (Pedal_info *p = info_list_; p && p->name_; p++)
     {
-      if (Note_column::has_interface (info.grob ()))
+      if (p->line_spanner_)
 	{
-	  if (p->line_spanner_)
-	    {
-	      Side_position_interface::add_support (p->line_spanner_, info.grob ());
-	      add_bound_item (p->line_spanner_, info.grob ());
-	    }
-	  if (p->bracket_)
-	    add_bound_item (p->bracket_, info.grob ());
-	  if (p->finished_bracket_)
-	    add_bound_item (p->finished_bracket_, info.grob ());
+	  Side_position_interface::add_support (p->line_spanner_, info.grob ());
+	  add_bound_item (p->line_spanner_, info.grob ());
 	}
+      if (p->bracket_)
+	add_bound_item (p->bracket_, info.grob ());
+      if (p->finished_bracket_)
+	add_bound_item (p->finished_bracket_, info.grob ());
     }
 }
 
@@ -526,12 +523,12 @@ Piano_pedal_engraver::typeset_all (Pedal_info *p)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Piano_pedal_engraver,note_column);
 ADD_TRANSLATOR (Piano_pedal_engraver,
 		/* descr */ "Engrave piano pedal symbols and brackets.",
 		/* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
 		/* accepts */ "pedal-event",
-		/* acks  */ "note-column-interface",
+		/* acks  */ "",
 		/* reads */ "currentCommandColumn "
 		"pedalSostenutoStrings pedalSustainStrings "
 		"pedalUnaCordaStrings pedalSostenutoStyle "
diff --git a/lily/pitched-trill-engraver.cc b/lily/pitched-trill-engraver.cc
index 38cba0810a..c29adc745d 100644
--- a/lily/pitched-trill-engraver.cc
+++ b/lily/pitched-trill-engraver.cc
@@ -26,7 +26,10 @@ public:
   TRANSLATOR_DECLARATIONS(Pitched_trill_engraver);
   
 protected:
-  virtual void acknowledge_grob (Grob_info);
+ 
+  DECLARE_ACKNOWLEDGER( note_head);
+  DECLARE_ACKNOWLEDGER( dots);
+  DECLARE_ACKNOWLEDGER( text_spanner);
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual bool try_music (Music*);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
@@ -49,19 +52,24 @@ Pitched_trill_engraver::Pitched_trill_engraver ()
 }
 
 void
-Pitched_trill_engraver::acknowledge_grob (Grob_info info)
+Pitched_trill_engraver::acknowledge_dots (Grob_info info)
+{
+  heads_.push (info.grob ());
+}
+void
+Pitched_trill_engraver::acknowledge_note_head (Grob_info info)
+{
+  heads_.push (info.grob ());
+}
+ 
+void
+Pitched_trill_engraver::acknowledge_text_spanner (Grob_info info)
 {
   Music *mus = info.music_cause ();
-
-  if (Note_head::has_interface (info.grob ())
-      || Dots::has_interface (info.grob ()))
-    {
-      heads_.push (info.grob ());
-    }
-  else if (mus
-	   && mus->is_mus_type ("trill-span-event")
-	   && to_dir (mus->get_property ("span-direction")) == START
-	   && unsmob_pitch (mus->get_property ("trill-pitch")))
+  if (mus
+      && mus->is_mus_type ("trill-span-event")
+      && to_dir (mus->get_property ("span-direction")) == START
+      && unsmob_pitch (mus->get_property ("trill-pitch")))
     {
       make_trill (mus);
     }
@@ -143,11 +151,13 @@ Pitched_trill_engraver::try_music (Music *)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Pitched_trill_engraver, note_head);
+ADD_ACKNOWLEDGER(Pitched_trill_engraver, dots);
+ADD_ACKNOWLEDGER(Pitched_trill_engraver, text_spanner);
 ADD_TRANSLATOR (Pitched_trill_engraver,
 		/* descr */ "Print the bracketed notehead after a notehead with trill.",
 		/* creats*/ "TrillPitchHead TrillPitchAccidental TrillPitchGroup",
 		/* accepts */ "",
-		/* acks  */ "script-interface text-spanner-interface dots-interface note-head-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/rhythmic-column-engraver.cc b/lily/rhythmic-column-engraver.cc
index de2fcc46fa..d4b8a5c826 100644
--- a/lily/rhythmic-column-engraver.cc
+++ b/lily/rhythmic-column-engraver.cc
@@ -13,6 +13,8 @@
 #include "dot-column.hh"
 #include "pointer-group-interface.hh"
 
+#include "translator.icc"
+
 /*
   this engraver  glues together stems, rests and note heads into a NoteColumn
   grob.
@@ -50,7 +52,9 @@ class Rhythmic_column_engraver : public Engraver
   TRANSLATOR_DECLARATIONS (Rhythmic_column_engraver);
 protected:
 
-  virtual void acknowledge_grob (Grob_info);
+DECLARE_ACKNOWLEDGER(dot_column);
+DECLARE_ACKNOWLEDGER(stem);
+DECLARE_ACKNOWLEDGER(rhythmic_head);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
@@ -111,23 +115,21 @@ Rhythmic_column_engraver::process_acknowledged ()
 }
 
 void
-Rhythmic_column_engraver::acknowledge_grob (Grob_info i)
+Rhythmic_column_engraver::acknowledge_stem (Grob_info i)
 {
-  Item *item = dynamic_cast<Item *> (i.grob ());
-  if (!item || item->get_parent (X_AXIS))
-    return;
-  if (Stem::has_interface (item))
-    {
-      stem_ = item;
-    }
-  else if (Rhythmic_head::has_interface (item))
-    {
-      rheads_.push (item);
-    }
-  else if (Dot_column::has_interface (item))
-    {
-      dotcol_ = item;
-    }
+  stem_ = i.grob();
+}
+
+void
+Rhythmic_column_engraver::acknowledge_rhythmic_head (Grob_info i)
+{
+  rheads_.push (i.grob ());
+}
+
+void
+Rhythmic_column_engraver::acknowledge_dot_column (Grob_info i)
+{
+  dotcol_ = i.grob ();
 }
 
 void
@@ -145,12 +147,15 @@ Rhythmic_column_engraver::stop_translation_timestep ()
   stem_ = 0;
 }
 
-#include "translator.icc"
+
+ADD_ACKNOWLEDGER(Rhythmic_column_engraver,dot_column);
+ADD_ACKNOWLEDGER(Rhythmic_column_engraver,stem);
+ADD_ACKNOWLEDGER(Rhythmic_column_engraver,rhythmic_head);
 
 ADD_TRANSLATOR (Rhythmic_column_engraver,
 		/* descr */ "Generates NoteColumn, an objects that groups stems, noteheads and rests.",
 		/* creats*/ "NoteColumn NoteSpacing",
 		/* accepts */ "",
-		/* acks  */ "stem-interface rhythmic-head-interface dot-column-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/script-column-engraver.cc b/lily/script-column-engraver.cc
index 78cefe92f5..e95fd4fd41 100644
--- a/lily/script-column-engraver.cc
+++ b/lily/script-column-engraver.cc
@@ -24,7 +24,7 @@ class Script_column_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Script_column_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(side_position);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
@@ -42,10 +42,10 @@ Script_column_engraver::stop_translation_timestep ()
 }
 
 void
-Script_column_engraver::acknowledge_grob (Grob_info inf)
+Script_column_engraver::acknowledge_side_position (Grob_info inf)
 {
   Item *thing = dynamic_cast<Item *> (inf.grob ());
-  if (thing && Side_position_interface::has_interface (inf.grob ())) // ugh FIXME
+  if (thing)
     {
       if (!Item::is_breakable (thing)
 	  && Side_position_interface::get_axis (inf.grob ()) == Y_AXIS)
@@ -70,11 +70,11 @@ Script_column_engraver::process_acknowledged ()
       scripts_.clear ();
     }
 }
-
+ADD_ACKNOWLEDGER(Script_column_engraver, side_position);
 ADD_TRANSLATOR (Script_column_engraver,
 		/* descr */ "",
 		/* creats*/ "ScriptColumn",
 		/* accepts */ "",
-		/* acks  */ "side-position-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/script-engraver.cc b/lily/script-engraver.cc
index 9f2f760d9f..6925471460 100644
--- a/lily/script-engraver.cc
+++ b/lily/script-engraver.cc
@@ -41,7 +41,11 @@ protected:
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER( slur);
+  DECLARE_ACKNOWLEDGER( rhythmic_head);
+  DECLARE_ACKNOWLEDGER( stem);
+  DECLARE_ACKNOWLEDGER( note_column);
 
 public:
   TRANSLATOR_DECLARATIONS (Script_engraver);
@@ -61,8 +65,8 @@ Script_engraver::try_music (Music *m)
       int script_count = scripts_.size ();
       for (int i = 0; i < script_count; i++)
 	if (ly_is_equal (scripts_[i].event_
-			  ->get_property ("articulation-type"),
-			  m->get_property ("articulation-type")))
+			 ->get_property ("articulation-type"),
+			 m->get_property ("articulation-type")))
 	  return true;
 
       Script_tuple t;
@@ -147,9 +151,8 @@ void make_script_from_event (Grob *p, bool *follow, Context *tg,
 void
 Script_engraver::process_music ()
 {
-  int script_count = scripts_.size ();
-  for (int i = 0; i < script_count; i++)
-    {
+  for (int i = 0; i < scripts_.size(); i++)
+     {
       Music *m = scripts_[i].event_;
 
       Grob *p = make_item ("Script", m->self_scm ());
@@ -166,29 +169,31 @@ Script_engraver::process_music ()
     }
 }
 
+
 void
-Script_engraver::acknowledge_grob (Grob_info info)
+Script_engraver::acknowledge_stem (Grob_info info)
 {
   int script_count = scripts_.size ();
-  if (Stem::has_interface (info.grob ()))
+  for (int i = 0; i < script_count; i++)
     {
-      for (int i = 0; i < script_count; i++)
-	{
-	  Grob *e = scripts_[i].script_;
+      Grob *e = scripts_[i].script_;
 
-	  if (to_dir (e->get_property ("side-relative-direction")))
-	    e->set_object ("direction-source", info.grob ()->self_scm ());
+      if (to_dir (e->get_property ("side-relative-direction")))
+	e->set_object ("direction-source", info.grob ()->self_scm ());
 
-	  /* FIXME: add dependency */
-	  e->add_dependency (info.grob ());
-	  Side_position_interface::add_support (e, info.grob ());
-	}
+      /* FIXME: add dependency */
+      e->add_dependency (info.grob ());
+      Side_position_interface::add_support (e, info.grob ());
     }
-  else if (Rhythmic_head::has_interface (info.grob ())
-	   && info.music_cause ())
+}
+
+void
+Script_engraver::acknowledge_rhythmic_head (Grob_info info)
+{
+  if(info.music_cause ())
     {
-      for (int i = 0; i < script_count; i++)
-	{
+     for (int i = 0; i < scripts_.size(); i++)
+ 	{
 	  Grob *e = scripts_[i].script_;
 
 	  if (Side_position_interface::get_axis (e) == X_AXIS
@@ -200,25 +205,32 @@ Script_engraver::acknowledge_grob (Grob_info info)
 	  Side_position_interface::add_support (e, info.grob ());
 	}
     }
-  else if (Note_column::has_interface (info.grob ()))
-    {
-      /* Make note column the parent of the script.  That is not
-	 correct, but due to seconds in a chord, noteheads may be
-	 swapped around horizontally.
+}
 
-	 As the note head to put it on is not known now, postpone this
-	 decision to Script_interface::before_line_breaking ().  */
-      for (int i = 0; i < script_count; i++)
-	{
-	  Grob *e = scripts_[i].script_;
+void
+Script_engraver::acknowledge_note_column (Grob_info info)
+{
+  /* Make note column the parent of the script.  That is not
+     correct, but due to seconds in a chord, noteheads may be
+     swapped around horizontally.
+
+     As the note head to put it on is not known now, postpone this
+     decision to Script_interface::before_line_breaking ().  */
+  
+  for (int i = 0; i < scripts_.size(); i++)
+    {
+      Grob *e = scripts_[i].script_;
 
-	  if (!e->get_parent (X_AXIS)
-	      && Side_position_interface::get_axis (e) == Y_AXIS)
-	    e->set_parent (info.grob (), X_AXIS);
-	}
+      if (!e->get_parent (X_AXIS)
+	  && Side_position_interface::get_axis (e) == Y_AXIS)
+	e->set_parent (info.grob (), X_AXIS);
     }
-  else if (Slur::has_interface (info.grob ()))
-    slur_ = dynamic_cast<Spanner *> (info.grob ());
+}
+ 
+void
+Script_engraver::acknowledge_slur (Grob_info info)
+{
+  slur_ = info.spanner ();
 }
 
 void
@@ -239,11 +251,15 @@ Script_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Script_engraver, slur);
+ADD_ACKNOWLEDGER(Script_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER(Script_engraver, stem);
+ADD_ACKNOWLEDGER(Script_engraver, note_column);
+
 ADD_TRANSLATOR (Script_engraver,
 		/* descr */ "Handles note scripted articulations.",
 		/* creats*/ "Script",
 		/* accepts */ "script-event articulation-event",
-		/* acks  */ "stem-interface rhythmic-head-interface "
-		"slur-interface note-column-interface",
+		/* acks  */ "",
 		/* reads */ "scriptDefinitions",
 		/* write */ "");
diff --git a/lily/separating-line-group-engraver.cc b/lily/separating-line-group-engraver.cc
index 415f3aa3f5..09214afeb0 100644
--- a/lily/separating-line-group-engraver.cc
+++ b/lily/separating-line-group-engraver.cc
@@ -19,6 +19,8 @@
 #include "grob-array.hh"
 #include "pointer-group-interface.hh"
 
+#include "translator.icc"
+
 struct Spacings
 {
   Item *staff_spacing_;
@@ -52,7 +54,7 @@ protected:
 
   Spanner *sep_span_;
 
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(item);
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
@@ -106,7 +108,7 @@ Separating_line_group_engraver::finalize ()
 }
 
 void
-Separating_line_group_engraver::acknowledge_grob (Grob_info i)
+Separating_line_group_engraver::acknowledge_item (Grob_info i)
 {
   Item *it = dynamic_cast<Item *> (i.grob ());
   if (!it)
@@ -221,12 +223,11 @@ Separating_line_group_engraver::stop_translation_timestep ()
   musical_item_ = 0;
 }
 
-#include "translator.icc"
-
+ADD_ACKNOWLEDGER(Separating_line_group_engraver, item);
 ADD_TRANSLATOR (Separating_line_group_engraver,
 		/* descr */ "Generates objects for computing spacing parameters.",
 		/* creats*/ "SeparationItem SeparatingGroupSpanner StaffSpacing",
 		/* accepts */ "",
-		/* acks  */ "item-interface",
+		/* acks  */ "",
 		/* reads */ "createSpacing",
 		/* write */ "breakableSeparationItem");
diff --git a/lily/slur-engraver.cc b/lily/slur-engraver.cc
index cb1da18560..8579bd8064 100644
--- a/lily/slur-engraver.cc
+++ b/lily/slur-engraver.cc
@@ -29,7 +29,14 @@ class Slur_engraver : public Engraver
 
 protected:
   virtual bool try_music (Music *);
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(note_column);
+  DECLARE_ACKNOWLEDGER(accidental);
+  DECLARE_ACKNOWLEDGER(fingering);
+  DECLARE_ACKNOWLEDGER(script);
+  DECLARE_ACKNOWLEDGER(tie);
+  DECLARE_ACKNOWLEDGER(text_script);
+  void acknowledge_extra_object (Grob_info);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void finalize ();
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -70,42 +77,76 @@ Slur_engraver::set_melisma (bool m)
 }
 
 void
-Slur_engraver::acknowledge_grob (Grob_info info)
+Slur_engraver::acknowledge_note_column (Grob_info info)
 {
   Grob *e = info.grob ();
-  if (Note_column::has_interface (info.grob ()))
+  for (int i = slurs_.size (); i--;)
+    Slur::add_column (slurs_[i], e);
+  for (int i = end_slurs_.size (); i--;)
+    Slur::add_column (end_slurs_[i], e);
+}
+
+void
+Slur_engraver::acknowledge_extra_object (Grob_info info)
+{
+  Grob*e = info.grob ();
+  SCM inside = e->get_property ("inside-slur");
+  if (Tie::has_interface (e)
+      || to_boolean (inside))
     {
       for (int i = slurs_.size (); i--;)
-	Slur::add_column (slurs_[i], e);
+	Slur::add_extra_encompass (slurs_[i], e);
       for (int i = end_slurs_.size (); i--;)
-	Slur::add_column (end_slurs_[i], e);
+	Slur::add_extra_encompass (end_slurs_[i], e);
     }
-  else
+  else if (inside == SCM_BOOL_F)
     {
-      SCM inside = e->get_property ("inside-slur");
-      if (Tie::has_interface (e)
-	  || to_boolean (inside))
-	{
-	  for (int i = slurs_.size (); i--;)
-	    Slur::add_extra_encompass (slurs_[i], e);
-	  for (int i = end_slurs_.size (); i--;)
-	    Slur::add_extra_encompass (end_slurs_[i], e);
-	}
-      else if (inside == SCM_BOOL_F)
+      Grob *slur = slurs_.size () ? slurs_[0] : 0;
+      slur = (end_slurs_.size () && !slur)
+	? end_slurs_[0] : slur;
+
+      if (slur)
 	{
-	  Grob *slur = slurs_.size () ? slurs_[0] : 0;
-	  slur = (end_slurs_.size () && !slur)
-	    ? end_slurs_[0] : slur;
-
-	  if (slur)
-	    {
-	      e->add_offset_callback (Slur::outside_slur_callback_proc, Y_AXIS);
-	      e->set_object ("slur", slur->self_scm ());
-	    }
+	  e->add_offset_callback (Slur::outside_slur_callback_proc, Y_AXIS);
+	  e->set_object ("slur", slur->self_scm ());
 	}
     }
 }
 
+void
+Slur_engraver::acknowledge_accidental (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+
+void
+Slur_engraver::acknowledge_fingering (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_engraver::acknowledge_script (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_engraver::acknowledge_text_script (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_engraver::acknowledge_tie (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+
+
+
 void
 Slur_engraver::finalize ()
 {
@@ -158,10 +199,16 @@ Slur_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Slur_engraver,note_column);
+ADD_ACKNOWLEDGER(Slur_engraver,accidental);
+ADD_ACKNOWLEDGER(Slur_engraver,fingering)
+ADD_ACKNOWLEDGER(Slur_engraver,script);
+ADD_ACKNOWLEDGER(Slur_engraver,tie);
+ADD_ACKNOWLEDGER(Slur_engraver,text_script);
 ADD_TRANSLATOR (Slur_engraver,
 		/* descr */ "Build slurs grobs from slur events",
 		/* creats*/ "Slur",
 		/* accepts */ "slur-event",
-		/* acks  */ "note-column-interface accidental-interface fingering-interface script-interface tie-interface text-script-interface",
+		/* acks  */ "",
 		/* reads */ "slurMelismaBusy doubleSlurs",
 		/* write */ "");
diff --git a/lily/spacing-engraver.cc b/lily/spacing-engraver.cc
index b2b27ff282..5d51b2f394 100644
--- a/lily/spacing-engraver.cc
+++ b/lily/spacing-engraver.cc
@@ -46,7 +46,9 @@ class Spacing_engraver : public Engraver
 
   TRANSLATOR_DECLARATIONS (Spacing_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(staff_spacing);
+  DECLARE_ACKNOWLEDGER(note_spacing);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -94,15 +96,22 @@ Spacing_engraver::finalize ()
 }
 
 void
-Spacing_engraver::acknowledge_grob (Grob_info i)
+Spacing_engraver::acknowledge_note_spacing (Grob_info i)
 {
-  if (Note_spacing::has_interface (i.grob ()) || Staff_spacing::has_interface (i.grob ()))
-    {
-      Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
-    }
+  Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
+}
 
+void
+Spacing_engraver::acknowledge_staff_spacing (Grob_info i)
+{
+  Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
+}
+  
+void
+Spacing_engraver::acknowledge_rhythmic_head (Grob_info i)
+{
   if (i.grob ()->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))
-      || i.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-event")))
+      || i.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
     return;
 
   /*
@@ -174,10 +183,14 @@ Spacing_engraver::start_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Spacing_engraver,staff_spacing);
+ADD_ACKNOWLEDGER(Spacing_engraver,note_spacing);
+ADD_ACKNOWLEDGER(Spacing_engraver,rhythmic_head);
+  
 ADD_TRANSLATOR (Spacing_engraver,
 		/* descr */ "make a SpacingSpanner and do bookkeeping of shortest starting and playing notes  ",
 		/* creats*/ "SpacingSpanner",
 		/* accepts */ "",
-		/* acks  */ "grob-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/span-arpeggio-engraver.cc b/lily/span-arpeggio-engraver.cc
index 69736c2f83..16846558ee 100644
--- a/lily/span-arpeggio-engraver.cc
+++ b/lily/span-arpeggio-engraver.cc
@@ -22,9 +22,9 @@ class Span_arpeggio_engraver : public Engraver
 {
 public:
   TRANSLATOR_DECLARATIONS (Span_arpeggio_engraver);
+  DECLARE_ACKNOWLEDGER(arpeggio);
 
 protected:
-  virtual void acknowledge_grob (Grob_info);
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 
@@ -39,10 +39,9 @@ Span_arpeggio_engraver::Span_arpeggio_engraver ()
 }
 
 void
-Span_arpeggio_engraver::acknowledge_grob (Grob_info info)
+Span_arpeggio_engraver::acknowledge_arpeggio (Grob_info info)
 {
-  if (Arpeggio::has_interface (info.grob ())
-      && info.origin_contexts (this).size ()) // huh? what's this test for? 
+  if (info.origin_contexts (this).size ()) // huh? what's this test for? 
     {
       arpeggios_.push (info.grob ());
     }
@@ -100,10 +99,11 @@ Span_arpeggio_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Span_arpeggio_engraver,arpeggio);
 ADD_TRANSLATOR (Span_arpeggio_engraver,
 		/* descr */ "",
 		/* creats*/ "Arpeggio",
 		/* accepts */ "",
-		/* acks  */ "arpeggio-interface",
+		/* acks  */ "",
 		/* reads */ "connectArpeggios",
 		/* write */ "");
diff --git a/lily/span-bar-engraver.cc b/lily/span-bar-engraver.cc
index f98f8d3214..645e6d7eb0 100644
--- a/lily/span-bar-engraver.cc
+++ b/lily/span-bar-engraver.cc
@@ -27,7 +27,7 @@ class Span_bar_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Span_bar_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(bar_line);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
 };
 
@@ -37,7 +37,7 @@ Span_bar_engraver::Span_bar_engraver ()
 }
 
 void
-Span_bar_engraver::acknowledge_grob (Grob_info i)
+Span_bar_engraver::acknowledge_bar_line (Grob_info i)
 {
   int depth = i.origin_contexts (this).size ();
   if (depth && Bar_line::has_interface (i.grob ()))
@@ -74,11 +74,12 @@ Span_bar_engraver::stop_translation_timestep ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Span_bar_engraver, bar_line);
 ADD_TRANSLATOR (Span_bar_engraver,
 		/* descr */ "This engraver makes cross-staff barlines: It catches all normal "
 		"bar lines, and draws a single span-bar across them.",
 		/* creats*/ "SpanBar",
 		/* accepts */ "",
-		/* acks  */ "bar-line-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/staff-collecting-engraver.cc b/lily/staff-collecting-engraver.cc
index 5784dd79c7..b1924090bc 100644
--- a/lily/staff-collecting-engraver.cc
+++ b/lily/staff-collecting-engraver.cc
@@ -15,7 +15,7 @@ class Staff_collecting_engraver : public Engraver
 {
 public:
   TRANSLATOR_DECLARATIONS (Staff_collecting_engraver);
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(staff_symbol);
 };
 
 Staff_collecting_engraver::Staff_collecting_engraver ()
@@ -23,24 +23,22 @@ Staff_collecting_engraver::Staff_collecting_engraver ()
 }
 
 void
-Staff_collecting_engraver::acknowledge_grob (Grob_info gi)
+Staff_collecting_engraver::acknowledge_staff_symbol (Grob_info gi)
 {
-  if (Staff_symbol::has_interface (gi.grob ()))
-    {
-      SCM staffs = get_property ("stavesFound");
-      staffs = scm_cons (gi.grob ()->self_scm (), staffs);
+  SCM staffs = get_property ("stavesFound");
+  staffs = scm_cons (gi.grob ()->self_scm (), staffs);
 
-      context ()->set_property ("stavesFound", staffs);
-    }
+  context ()->set_property ("stavesFound", staffs);
 }
 
 #include "translator.icc"
+ADD_ACKNOWLEDGER(Staff_collecting_engraver,staff_symbol);
 
 ADD_TRANSLATOR (Staff_collecting_engraver,
 		/* descr */ "Maintain the stavesFound variable",
 
 		/* creats*/ "",
 		/* accepts */ "",
-		/* acks  */ "staff-symbol-interface",
+		/* acks  */ "",
 		/* reads */ "stavesFound",
 		/* write */ "stavesFound");
diff --git a/lily/staff-symbol-engraver.cc b/lily/staff-symbol-engraver.cc
index f9e79a6b94..0b5cb6640d 100644
--- a/lily/staff-symbol-engraver.cc
+++ b/lily/staff-symbol-engraver.cc
@@ -109,12 +109,12 @@ Staff_symbol_engraver::acknowledge_grob (Grob_info s)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Staff_symbol_engraver,grob);
 ADD_TRANSLATOR (Staff_symbol_engraver,
 		/* descr */ "Create the constellation of five (default) "
 		"staff lines.",
 		/* creats*/ "StaffSymbol",
 		/* accepts */ "staff-span-event",
-		/* acks  */ "grob-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc
index e9369c1842..9248ef41cf 100644
--- a/lily/stem-engraver.cc
+++ b/lily/stem-engraver.cc
@@ -33,7 +33,7 @@ class Stem_engraver : public Engraver
 protected:
   void make_stem (Grob_info);
 
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual bool try_music (Music *);
 };
@@ -107,33 +107,30 @@ Stem_engraver::make_stem (Grob_info gi)
 }
 
 void
-Stem_engraver::acknowledge_grob (Grob_info gi)
+Stem_engraver::acknowledge_rhythmic_head (Grob_info gi)
 {
-  if (Rhythmic_head::has_interface (gi.grob ()))
-    {
-      if (Rhythmic_head::get_stem (gi.grob ()))
-	return;
-
-      Music *cause = gi.music_cause ();
-      if (!cause)
-	return;
-      Duration *d = unsmob_duration (cause->get_property ("duration"));
-      if (!d)
-	return ;
+  if (Rhythmic_head::get_stem (gi.grob ()))
+    return;
+
+  Music *cause = gi.music_cause ();
+  if (!cause)
+    return;
+  Duration *d = unsmob_duration (cause->get_property ("duration"));
+  if (!d)
+    return ;
       
-      if (!stem_)
-	make_stem (gi);
+  if (!stem_)
+    make_stem (gi);
       
-      if (Stem::duration_log (stem_) != d->duration_log ())
-	{
-	  // FIXME: 
-	  gi.music_cause ()->origin ()->warning (_f ("adding note head to incompatible stem (type = %d)",
-						     1 << Stem::duration_log (stem_)));
-	  gi.music_cause ()->origin ()->warning (_f ("maybe input should specify polyphonic voices"));
-	}
-
-      Stem::add_head (stem_, gi.grob ());
+  if (Stem::duration_log (stem_) != d->duration_log ())
+    {
+      // FIXME: 
+      gi.music_cause ()->origin ()->warning (_f ("adding note head to incompatible stem (type = %d)",
+						 1 << Stem::duration_log (stem_)));
+      gi.music_cause ()->origin ()->warning (_f ("maybe input should specify polyphonic voices"));
     }
+
+  Stem::add_head (stem_, gi.grob ());
 }
 
 void
@@ -172,12 +169,12 @@ Stem_engraver::try_music (Music *m)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Stem_engraver,rhythmic_head);
 ADD_TRANSLATOR (Stem_engraver,
 		/* descr */ "Create stems and single-stem tremolos.  It also works together with "
 		"the beam engraver for overriding beaming.",
 		/* creats*/ "Stem StemTremolo",
 		/* accepts */ "tremolo-event",
-		/* acks  */ "rhythmic-head-interface",
+		/* acks  */ "",
 		/* reads */ "tremoloFlags stemLeftBeamCount stemRightBeamCount",
 		/* write */ "");
diff --git a/lily/system-start-delimiter-engraver.cc b/lily/system-start-delimiter-engraver.cc
index 1646ee5477..5a43fc0767 100644
--- a/lily/system-start-delimiter-engraver.cc
+++ b/lily/system-start-delimiter-engraver.cc
@@ -21,38 +21,38 @@ public:
 
 protected:
   Spanner *delim_;
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(system_start_delimiter);
+  DECLARE_ACKNOWLEDGER(staff_symbol);
+
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual void finalize ();
 };
 
 void
-System_start_delimiter_engraver::acknowledge_grob (Grob_info inf)
+System_start_delimiter_engraver::acknowledge_staff_symbol (Grob_info inf)
 {
-  if (Staff_symbol::has_interface (inf.grob ()))
-    {
-      /*
-	don't add as Axis_group_interface::add_element (delim_, ),
-	because that would set the parent as well */
+  /*
+    don't add as Axis_group_interface::add_element (delim_, ),
+    because that would set the parent as well */
 
-      Pointer_group_interface::add_grob (delim_, ly_symbol2scm ("elements"), inf.grob ());
-    }
-  else if (System_start_delimiter::has_interface (inf.grob ()))
-    {
-      SCM gl = inf.grob ()->get_property ("glyph");
-      SCM my_gl = delim_->get_property ("glyph");
+  Pointer_group_interface::add_grob (delim_, ly_symbol2scm ("elements"), inf.grob ());
+}
+void
+System_start_delimiter_engraver::acknowledge_system_start_delimiter (Grob_info inf)
+{
+  SCM gl = inf.grob ()->get_property ("glyph");
+  SCM my_gl = delim_->get_property ("glyph");
 
-      /*
-	UGH UGH
-      */
-      if (scm_is_string (gl) && ly_is_equal (gl, scm_makfrom0str ("brace"))
-	  && scm_is_string (my_gl) && ly_is_equal (my_gl, scm_makfrom0str ("bracket")))
-	inf.grob ()->translate_axis (-0.8, X_AXIS); // ugh
-      else if (scm_is_string (gl) && ly_is_equal (gl, scm_makfrom0str ("bracket"))
-	       && scm_is_string (my_gl) && ly_is_equal (my_gl, scm_makfrom0str ("bracket")))
-	{
-	  inf.grob ()->translate_axis (-0.8, X_AXIS); // ugh
-	}
+  /*
+    UGH UGH
+  */
+  if (scm_is_string (gl) && ly_is_equal (gl, scm_makfrom0str ("brace"))
+      && scm_is_string (my_gl) && ly_is_equal (my_gl, scm_makfrom0str ("bracket")))
+    inf.grob ()->translate_axis (-0.8, X_AXIS); // ugh
+  else if (scm_is_string (gl) && ly_is_equal (gl, scm_makfrom0str ("bracket"))
+	   && scm_is_string (my_gl) && ly_is_equal (my_gl, scm_makfrom0str ("bracket")))
+    {
+      inf.grob ()->translate_axis (-0.8, X_AXIS); // ugh
     }
 }
 
@@ -84,10 +84,13 @@ System_start_delimiter_engraver::finalize ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(System_start_delimiter_engraver, system_start_delimiter);
+ADD_ACKNOWLEDGER(System_start_delimiter_engraver, staff_symbol);
+
 ADD_TRANSLATOR (System_start_delimiter_engraver,
 		/* descr */ "Creates a system start delimiter (ie. SystemStart@{Bar, Brace, Bracket@} spanner",
 		/* creats*/ "SystemStartBar SystemStartBrace SystemStartBracket",
 		/* accepts */ "",
-		/* acks  */ "system-start-delimiter-interface staff-symbol-interface",
+		/* acks  */ "",
 		/* reads */ "systemStartDelimiter",
 		/* write */ "");
diff --git a/lily/tab-staff-symbol-engraver.cc b/lily/tab-staff-symbol-engraver.cc
index 1227d2e0f0..32020eee13 100644
--- a/lily/tab-staff-symbol-engraver.cc
+++ b/lily/tab-staff-symbol-engraver.cc
@@ -37,11 +37,12 @@ Tab_staff_symbol_engraver::Tab_staff_symbol_engraver ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Tab_staff_symbol_engraver,grob);
 ADD_TRANSLATOR (Tab_staff_symbol_engraver,
 		/* descr */ "Create a staff-symbol, but look at stringTunings for the number of lines."
 		"staff lines.",
 		/* creats*/ "StaffSymbol",
 		/* accepts */ "staff-span-event",
-		/* acks  */ "grob-interface",
+		/* acks  */ "",
 		/* reads */ "stringTunings",
 		/* write */ "");
diff --git a/lily/text-engraver.cc b/lily/text-engraver.cc
index b9f9509304..bdd0ba8306 100644
--- a/lily/text-engraver.cc
+++ b/lily/text-engraver.cc
@@ -26,7 +26,9 @@ protected:
   virtual bool try_music (Music *m);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_acknowledged ();
-  virtual void acknowledge_grob (Grob_info);
+
+  DECLARE_ACKNOWLEDGER(stem);
+  DECLARE_ACKNOWLEDGER(rhythmic_head);
 };
 
 bool
@@ -41,33 +43,31 @@ Text_engraver::try_music (Music *m)
 }
 
 void
-Text_engraver::acknowledge_grob (Grob_info inf)
+Text_engraver::acknowledge_rhythmic_head (Grob_info inf)
 {
-  if (Rhythmic_head::has_interface (inf.grob ()))
+  for (int i = 0; i < texts_.size (); i++)
     {
-      for (int i = 0; i < texts_.size (); i++)
-	{
-	  Grob *t = texts_[i];
-	  Side_position_interface::add_support (t, inf.grob ());
-
-	  /*
-	    ugh.
-	  */
-	  if (Side_position_interface::get_axis (t) == X_AXIS
-	      && !t->get_parent (Y_AXIS))
-	    t->set_parent (inf.grob (), Y_AXIS);
-	  else if (Side_position_interface::get_axis (t) == Y_AXIS
-		   && !t->get_parent (X_AXIS))
-	    t->set_parent (inf.grob (), X_AXIS);
-	}
+      Grob *t = texts_[i];
+      Side_position_interface::add_support (t, inf.grob ());
+
+      /*
+	ugh.
+      */
+      if (Side_position_interface::get_axis (t) == X_AXIS
+	  && !t->get_parent (Y_AXIS))
+	t->set_parent (inf.grob (), Y_AXIS);
+      else if (Side_position_interface::get_axis (t) == Y_AXIS
+	       && !t->get_parent (X_AXIS))
+	t->set_parent (inf.grob (), X_AXIS);
     }
+}
 
-  if (Stem::has_interface (inf.grob ()))
+void
+Text_engraver::acknowledge_stem (Grob_info inf)
+{
+  for (int i = 0; i < texts_.size (); i++)
     {
-      for (int i = 0; i < texts_.size (); i++)
-	{
-	  Side_position_interface::add_support (texts_[i], inf.grob ());
-	}
+      Side_position_interface::add_support (texts_[i], inf.grob ());
     }
 }
 
@@ -121,10 +121,12 @@ Text_engraver::Text_engraver ()
 
 #include "translator.icc"
 
+ADD_ACKNOWLEDGER(Text_engraver, stem);
+ADD_ACKNOWLEDGER(Text_engraver, rhythmic_head);
 ADD_TRANSLATOR (Text_engraver,
 		/* descr */ "Create text-scripts",
 		/* creats*/ "TextScript",
 		/* accepts */ "text-script-event",
-		/* acks  */ "rhythmic-head-interface stem-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/text-spanner-engraver.cc b/lily/text-spanner-engraver.cc
index 0a7a279a7b..110acce0a0 100644
--- a/lily/text-spanner-engraver.cc
+++ b/lily/text-spanner-engraver.cc
@@ -16,7 +16,7 @@ public:
   TRANSLATOR_DECLARATIONS (Text_spanner_engraver);
 protected:
   virtual void finalize ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_column);
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
@@ -86,12 +86,12 @@ Text_spanner_engraver::process_music ()
 }
 
 void
-Text_spanner_engraver::acknowledge_grob (Grob_info info)
+Text_spanner_engraver::acknowledge_note_column (Grob_info info)
 {
   Spanner *spans[2] ={span_, finished_};
   for (int i = 0; i < 2; i++)
     {
-      if (spans[i] && Note_column::has_interface (info.grob ()))
+      if (spans[i])
 	{
 	  Side_position_interface::add_support (spans[i], info.grob ());
 	  add_bound_item (spans[i], dynamic_cast<Item *> (info.grob ()));
@@ -140,11 +140,11 @@ Text_spanner_engraver::finalize ()
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Text_spanner_engraver,note_column);
 ADD_TRANSLATOR (Text_spanner_engraver,
 		/* descr */ "Create text spanner from a Music.",
 		/* creats*/ "TextSpanner",
 		/* accepts */ "text-span-event",
-		/* acks  */ "note-column-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc
index cf5364015c..d68c10457e 100644
--- a/lily/tie-engraver.cc
+++ b/lily/tie-engraver.cc
@@ -56,7 +56,7 @@ protected:
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   virtual void derived_mark () const;
   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(note_head);
   virtual bool try_music (Music *);
   PRECOMPUTED_VIRTUAL void process_music ();
   void typeset_tie (Grob *);
@@ -99,47 +99,44 @@ Tie_engraver::process_music ()
 }
 
 void
-Tie_engraver::acknowledge_grob (Grob_info i)
+Tie_engraver::acknowledge_note_head (Grob_info i)
 {
-  if (Note_head::has_interface (i.grob ()))
+  Grob *h = i.grob ();
+  now_heads_.push (h);
+  for (int i = heads_to_tie_.size (); i--;)
     {
-      Grob *h = i.grob ();
-      now_heads_.push (h);
-      for (int i = heads_to_tie_.size (); i--;)
+      Grob *th = heads_to_tie_[i].head_;
+      Music *right_mus = unsmob_music (h->get_property ("cause"));
+      Music *left_mus = unsmob_music (th->get_property ("cause"));
+
+      /*
+	maybe should check positions too.
+      */
+      if (right_mus && left_mus
+	  && ly_is_equal (right_mus->get_property ("pitch"),
+			  left_mus->get_property ("pitch")))
 	{
-	  Grob *th = heads_to_tie_[i].head_;
-	  Music *right_mus = unsmob_music (h->get_property ("cause"));
-	  Music *left_mus = unsmob_music (th->get_property ("cause"));
-
-	  /*
-	    maybe should check positions too.
-	  */
-	  if (right_mus && left_mus
-	      && ly_is_equal (right_mus->get_property ("pitch"),
-			       left_mus->get_property ("pitch")))
-	    {
-	      Grob *p = new Spanner (heads_to_tie_[i].tie_definition_,
-				     context ()->get_grob_key ("Tie"));
-	      announce_grob (p, heads_to_tie_[i].event_->self_scm ());
-	      Tie::set_interface (p); // cannot remove yet!
-
-	      Tie::set_head (p, LEFT, th);
-	      Tie::set_head (p, RIGHT, h);
-
-	      ties_.push (p);
-	      heads_to_tie_.del (i);
-	    }
-	}
+	  Grob *p = new Spanner (heads_to_tie_[i].tie_definition_,
+				 context ()->get_grob_key ("Tie"));
+	  announce_grob (p, heads_to_tie_[i].event_->self_scm ());
+	  Tie::set_interface (p); // cannot remove yet!
 
-      if (ties_.size () && ! tie_column_)
-	{
-	  tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
+	  Tie::set_head (p, LEFT, th);
+	  Tie::set_head (p, RIGHT, h);
+
+	  ties_.push (p);
+	  heads_to_tie_.del (i);
 	}
+    }
 
-      if (tie_column_)
-	for (int i = ties_.size (); i--;)
-	  Tie_column::add_tie (tie_column_, ties_[i]);
+  if (ties_.size () && ! tie_column_)
+    {
+      tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
     }
+
+  if (tie_column_)
+    for (int i = ties_.size (); i--;)
+      Tie_column::add_tie (tie_column_, ties_[i]);
 }
 
 void
@@ -209,11 +206,11 @@ Tie_engraver::typeset_tie (Grob *her)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Tie_engraver, note_head);
 ADD_TRANSLATOR (Tie_engraver,
 		/* descr */ "Generate ties between noteheads of equal pitch.",
 		/* creats*/ "Tie TieColumn",
 		/* accepts */ "tie-event",
-		/* acks  */ "rhythmic-head-interface",
+		/* acks  */ "",
 		/* reads */ "tieMelismaBusy",
 		/* write */ "");
diff --git a/lily/translator-dispatch-list.cc b/lily/translator-dispatch-list.cc
new file mode 100644
index 0000000000..11d3d62166
--- /dev/null
+++ b/lily/translator-dispatch-list.cc
@@ -0,0 +1,83 @@
+/*
+  translator-dispatch-list.cc -- implement Translator_dispatch_list
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "translator-dispatch-list.hh"
+
+#include "grob-info.hh"
+#include "engraver.hh"
+
+#include "ly-smobs.icc"
+
+void 
+Engraver_dispatch_list::apply (Grob_info gi)
+{
+  for (int i = 0; i < dispatch_entries_.size (); i++)
+    {
+      Engraver_dispatch_entry const &e (dispatch_entries_[i]);
+      if (e.engraver_ == gi.origin_translator ())
+	continue; 
+
+      (*e.function_) (e.engraver_, gi);
+    }
+}
+
+SCM
+Engraver_dispatch_list::create (SCM trans_list,
+				SCM iface_list)
+{
+  SCM retval = Engraver_dispatch_list().smobbed_copy ();
+  Engraver_dispatch_list * list = Engraver_dispatch_list::unsmob (retval);
+
+  Engraver_dispatch_entry entry;
+  bool found = false; 
+  for (SCM s = trans_list; scm_is_pair (s); s = scm_cdr (s))
+    {
+      Engraver * eng
+	= dynamic_cast<Engraver*> (unsmob_translator (scm_car (s)));
+
+      if (!eng)
+	continue;
+
+      entry.engraver_ = eng;
+      for (SCM i =  iface_list; scm_is_pair (i); i = scm_cdr (i))
+	{
+	  Engraver_void_function_engraver_grob_info ptr
+	    = eng->get_acknowledger (scm_car (i));
+	  if (ptr)
+	    {
+	      entry.function_ = ptr;
+	      list->dispatch_entries_.push (entry);
+	      found = true;
+	    }
+	  
+	}
+    }
+
+  
+  return found ? retval : SCM_BOOL_F;
+}
+
+SCM
+Engraver_dispatch_list::mark_smob (SCM x)
+{
+  (void)x;
+  return SCM_BOOL_F;
+}
+
+
+int
+Engraver_dispatch_list::print_smob (SCM x, SCM p, scm_print_state *)
+{
+  (void)x;
+  scm_puts ("#<Engraver_dispatch_list>", p);
+  return 1;
+}
+
+IMPLEMENT_SIMPLE_SMOBS(Engraver_dispatch_list);
+IMPLEMENT_DEFAULT_EQUAL_P(Engraver_dispatch_list);
diff --git a/lily/translator.cc b/lily/translator.cc
index d7c5fdf29c..46e735acbd 100644
--- a/lily/translator.cc
+++ b/lily/translator.cc
@@ -158,7 +158,7 @@ Translator::print_smob (SCM s, SCM port, scm_print_state *)
 }
 
 void
-add_acknowledger (Translator_void_method_ptr ptr,
+add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
 		  const char *func_name,
 		  Array<Acknowledge_information> *ack_array)
 {
@@ -167,7 +167,6 @@ add_acknowledger (Translator_void_method_ptr ptr,
 
   String interface_name(func_name);
 
-  interface_name = interface_name.substitute ("acknowledge_", "");
   interface_name = interface_name.substitute ('_', '-');
   interface_name += "-interface";
 
@@ -175,7 +174,7 @@ add_acknowledger (Translator_void_method_ptr ptr,
   ack_array->push (inf);
 }
 
-Translator_void_method_ptr 
+Engraver_void_function_engraver_grob_info
 generic_get_acknowledger (SCM sym, Array<Acknowledge_information> const *ack_array)
 {
   for (int i = 0; i < ack_array->size(); i++)
diff --git a/lily/vertical-align-engraver.cc b/lily/vertical-align-engraver.cc
index b19844acba..2cdd18d9d5 100644
--- a/lily/vertical-align-engraver.cc
+++ b/lily/vertical-align-engraver.cc
@@ -26,22 +26,22 @@ class Vertical_align_engraver : public Engraver
   
 public:
   TRANSLATOR_DECLARATIONS (Vertical_align_engraver);
+  DECLARE_ACKNOWLEDGER(axis_group);
 
 protected:
   virtual void derived_mark () const;
-  virtual void acknowledge_grob (Grob_info);
   PRECOMPUTED_VIRTUAL void process_music ();
   virtual void finalize ();
   virtual void initialize ();
 };
 
-
+ADD_ACKNOWLEDGER(Vertical_align_engraver, axis_group);
 ADD_TRANSLATOR (Vertical_align_engraver,
 		"Catch groups (staffs, lyrics lines, etc.) and stack "
 		"them vertically.",
 		/* creats*/ "VerticalAlignment",
 		/* accepts */ "",
-		/* acks  */ "axis-group-interface",
+		/* acks  */ "",
 		/* reads */ "",
 		/* write */ "");
 
@@ -95,7 +95,7 @@ Vertical_align_engraver::qualifies (Grob_info i) const
 }
 
 void
-Vertical_align_engraver::acknowledge_grob (Grob_info i)
+Vertical_align_engraver::acknowledge_axis_group (Grob_info i)
 {
   if (qualifies (i))
     {
diff --git a/lily/vertically-spaced-context-engraver.cc b/lily/vertically-spaced-context-engraver.cc
index f62fbe0ffe..63a7be9cd1 100644
--- a/lily/vertically-spaced-context-engraver.cc
+++ b/lily/vertically-spaced-context-engraver.cc
@@ -17,11 +17,11 @@ class Vertically_spaced_contexts_engraver : public Engraver
 {
   TRANSLATOR_DECLARATIONS(Vertically_spaced_contexts_engraver);
 protected:
-  virtual void acknowledge_grob (Grob_info);
   virtual void initialize ();
+  DECLARE_ACKNOWLEDGER(vertically_spaceable);
 
 private:
-  Grob * system_;
+  Grob *system_;
 };
 
 
@@ -38,10 +38,9 @@ Vertically_spaced_contexts_engraver::initialize ()
 }
 
 void
-Vertically_spaced_contexts_engraver::acknowledge_grob (Grob_info gi)
+Vertically_spaced_contexts_engraver::acknowledge_vertically_spaceable (Grob_info gi)
 {
-  if (Axis_group_interface::has_interface (gi.grob ())
-      && gi.grob ()->internal_has_interface (ly_symbol2scm ("vertically-spaceable-interface")))
+  if (Axis_group_interface::has_interface (gi.grob ()))
     {
       SCM spaceable = get_property ("verticallySpacedContexts");
       Context *orig = gi.origin_contexts (this)[0];
@@ -57,11 +56,11 @@ Vertically_spaced_contexts_engraver::acknowledge_grob (Grob_info gi)
 }
 
 #include "translator.icc"
-
+ADD_ACKNOWLEDGER(Vertically_spaced_contexts_engraver, vertically_spaceable);
 ADD_TRANSLATOR (Vertically_spaced_contexts_engraver,
 		/* descr */ "",
 		/* creats*/ "",
 		/* accepts */ "",
-		/* acks  */ "axis-group-interface",
+		/* acks  */ "",
 		/* reads */ "verticallySpacedContexts",
 		/* write */ "verticallySpacedContexts");
diff --git a/lily/volta-engraver.cc b/lily/volta-engraver.cc
index a344a8535d..3d4082821b 100644
--- a/lily/volta-engraver.cc
+++ b/lily/volta-engraver.cc
@@ -27,8 +27,12 @@ public:
   TRANSLATOR_DECLARATIONS (Volta_engraver);
 protected:
 
-  virtual void acknowledge_grob (Grob_info);
+  DECLARE_ACKNOWLEDGER(staff_symbol);
+  DECLARE_ACKNOWLEDGER(note_column);
+  DECLARE_ACKNOWLEDGER(bar_line);
+  
   virtual void finalize ();
+
   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
   PRECOMPUTED_VIRTUAL void process_music ();
 
@@ -161,34 +165,32 @@ Volta_engraver::process_music ()
 }
 
 void
-Volta_engraver::acknowledge_grob (Grob_info i)
+Volta_engraver::acknowledge_note_column (Grob_info i)
 {
-  if (Item *item = dynamic_cast<Item *> (i.grob ()))
-    {
-      if (Note_column::has_interface (item))
-	{
-	  if (volta_span_)
-	    Volta_bracket_interface::add_column (volta_span_, item);
-	}
-      if (Bar_line::has_interface (item))
-	{
-	  if (volta_span_)
-	    Volta_bracket_interface::add_bar (volta_span_, item);
-	  if (end_volta_span_)
-	    Volta_bracket_interface::add_bar (end_volta_span_, item);
-	}
-    }
-  else if (Staff_symbol::has_interface (i.grob ()))
-    {
-      /*
-	We only want to know about a single staff: then we add to the
-	support.  */
-      if (staff_ != SCM_EOL)
-	staff_ = SCM_UNDEFINED;
+  if (volta_span_)
+    Volta_bracket_interface::add_column (volta_span_, i.grob());
+}
 
-      if (staff_ != SCM_UNDEFINED)
-	staff_ = i.grob ()->self_scm ();
-    }
+void
+Volta_engraver::acknowledge_bar_line (Grob_info i)
+{
+  if (volta_span_)
+    Volta_bracket_interface::add_bar (volta_span_, i.item ());
+  if (end_volta_span_)
+    Volta_bracket_interface::add_bar (end_volta_span_, i.item ());
+}
+ 
+void
+Volta_engraver::acknowledge_staff_symbol (Grob_info i)
+{
+  /*
+    We only want to know about a single staff: then we add to the
+    support.  */
+  if (staff_ != SCM_EOL)
+    staff_ = SCM_UNDEFINED;
+
+  if (staff_ != SCM_UNDEFINED)
+    staff_ = i.grob ()->self_scm ();
 }
 
 void
@@ -232,11 +234,13 @@ Volta_engraver::stop_translation_timestep ()
 /*
   TODO: should attach volta to paper-column if no bar is found.
 */
-
+ADD_ACKNOWLEDGER(Volta_engraver, staff_symbol);
+ADD_ACKNOWLEDGER(Volta_engraver, note_column);
+ADD_ACKNOWLEDGER(Volta_engraver, bar_line);
 ADD_TRANSLATOR (Volta_engraver,
 		/* descr */ "Make volta brackets.",
 		/* creats*/ "VoltaBracket",
 		/* accepts */ "",
-		/* acks  */ "bar-line-interface staff-symbol-interface note-column-interface",
+		/* acks  */ "",
 		/* reads */ "repeatCommands voltaSpannerDuration stavesFound",
 		/* write */ "");
-- 
2.39.5