]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/listener.hh
562380c5764e6967790431fc9dac8f4c8c1bea50
[lilypond.git] / lily / include / listener.hh
1 /*
2   listener.hh -- declare Listener
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Erik Sandberg <mandolaerik@gmail.com>
7 */
8
9 #ifndef LISTENER_HH
10 #define LISTENER_HH
11
12 /*
13   Listeners
14
15   Listeners are used for stream event dispatching. If you want to
16   register a method as an event handler in a dispatcher, then you
17   must:
18
19   - declare the method using the DECLARE_LISTENER macro. 
20   class Foo
21   {
22     DECLARE_LISTENER (method);
23     ...
24   };
25   This macro declares the method to take a SCM as parameter, and to
26     return void. It also declares some other stuff that shouldn't be
27     touched.
28
29   - implement the method using IMPLEMENT_LISTENER:
30   IMPLEMENT_LISTENER (Foo, method)
31   void method (SCM e)
32   {
33     write ("Foo hears an event!");
34   }
35
36   - Extract a listener using GET_LISTENER (Foo->method)
37   - Register the method to the dispatcher using Dispatcher::register
38
39   Example:
40
41   Foo *foo = (...);
42   Stream_distributor *d = (...);
43   Listener l = GET_LISTENER (foo->method);
44   d->register_listener (l, "EventClass");
45   
46   Whenever d hears a stream-event ev of class "EventClass",
47   the implemented procedure is called.
48
49   Limitations:
50   - DECLARE_LISTENER currently only works inside smob classes.
51 */
52
53 #include "smobs.hh"
54
55 typedef struct {
56   void (*listen_callback) (void *, SCM);
57   void (*mark_callback) (void *);
58 } Listener_function_table;
59
60 class Listener {
61   void *target_;
62   Listener_function_table *type_;
63 public:
64   Listener (const void *target, Listener_function_table *type);
65   Listener (Listener const &other);
66   Listener ();
67
68   void listen (SCM ev) const;
69
70   bool operator == (Listener const &other) const
71   { return target_ == other.target_ && type_ == other.type_; }
72
73   DECLARE_SIMPLE_SMOBS (Listener,);
74 };
75 DECLARE_UNSMOB (Listener, listener);
76
77 #define IMPLEMENT_LISTENER(cl, method)                  \
78 void                                                    \
79 cl :: method ## _callback (void *self, SCM ev)          \
80 {                                                       \
81   cl *s = (cl *)self;                                   \
82   s->method (ev);                                       \
83 }                                                       \
84 void                                                    \
85 cl :: method ## _mark (void *self)                      \
86 {                                                       \
87   cl *s = (cl *)self;                                   \
88   scm_gc_mark (s->self_scm ());                         \
89 }                                                       \
90 Listener                                                \
91 cl :: method ## _listener () const                      \
92 {                                                       \
93   static Listener_function_table callbacks;             \
94   callbacks.listen_callback = &cl::method ## _callback; \
95   callbacks.mark_callback = &cl::method ## _mark;       \
96   return Listener (this, &callbacks);                   \
97 }
98
99 #define GET_LISTENER(proc) proc ## _listener ()
100
101 #define DECLARE_LISTENER(name)                          \
102   inline void name (SCM);                               \
103   static void name ## _callback (void *self, SCM ev);   \
104   static void name ## _mark (void *self);               \
105   Listener name ## _listener () const
106
107 #endif /* LISTENER_HH */