]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/listener.hh
Issue 4357/3: Run preparatory script replacing listener macros
[lilypond.git] / lily / include / listener.hh
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2005 Erik Sandberg <mandolaerik@gmail.com>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef LISTENER_HH
21 #define LISTENER_HH
22
23 /*
24   Listeners
25
26   Listeners are used for stream event dispatching. If you want to
27   register a method as an event handler in a dispatcher, then you
28   must:
29
30   - declare the method using the DECLARE_LISTENER macro.
31   class Foo
32   {
33     void method (SCM);
34     ...
35   };
36   This macro declares the method to take a SCM as parameter, and to
37     return void. It also declares some other stuff that shouldn't be
38     touched.
39
40   - implement the method using IMPLEMENT_LISTENER:
41   void method (SCM e)
42   {
43     write ("Foo hears an event!");
44   }
45
46   - Extract a listener using GET_LISTENER (Foo->method)
47   - Register the method to the dispatcher using Dispatcher::register
48
49   Example:
50
51   Foo *foo = (...);
52   Stream_distributor *d = (...);
53   Listener l = foo->GET_LISTENER (Foo, method);
54   d->register_listener (l, "EventClass");
55
56   Whenever d hears a stream-event ev of class "EventClass",
57   the implemented procedure is called.
58
59   Limitations:
60   - DECLARE_LISTENER currently only works inside smob classes.
61 */
62
63 #include "smobs.hh"
64
65 typedef struct
66 {
67   void (*listen_callback) (void *, SCM);
68   void (*mark_callback) (void *);
69   bool (*equal_callback) (void *, void *);
70 } Listener_function_table;
71
72 class Listener : public Simple_smob<Listener>
73 {
74 public:
75   static SCM equal_p (SCM, SCM);
76   SCM mark_smob ();
77   static const char type_p_name_[];
78 private:
79   void *target_;
80   Listener_function_table *type_;
81 public:
82   Listener (const void *target, Listener_function_table *type);
83   Listener (Listener const &other);
84   Listener ();
85
86   void listen (SCM ev) const;
87
88   LY_DECLARE_SMOB_PROC (1, 0, 0, (SCM self, SCM ev))
89   {
90     Listener::unsmob (self)->listen (ev);
91     return SCM_UNSPECIFIED;
92   }
93
94   bool operator == (Listener const &other) const
95   {
96     return type_ == other.type_
97            && (*type_->equal_callback) ((void *) target_, (void *) other.target_);
98   }
99
100 };
101
102 #define IMPLEMENT_LISTENER(cl, method)                  \
103 void                                                    \
104 cl :: method ## _callback (void *self, SCM ev)          \
105 {                                                       \
106   cl *s = (cl *)self;                                   \
107   s->method (ev);                                       \
108 }                                                       \
109 void                                                    \
110 cl :: method ## _mark (void *self)                      \
111 {                                                       \
112   cl *s = (cl *)self;                                   \
113   scm_gc_mark (s->self_scm ());                         \
114 }                                                       \
115 bool                                                    \
116 cl :: method ## _is_equal (void *a, void *b)            \
117 {                                                       \
118   return a == b;                                        \
119 }                                                       \
120 Listener                                                \
121 cl :: method ## _listener () const                      \
122 {                                                       \
123   static Listener_function_table callbacks;             \
124   callbacks.listen_callback = &cl::method ## _callback; \
125   callbacks.mark_callback = &cl::method ## _mark;       \
126   callbacks.equal_callback = &cl::method ## _is_equal;  \
127   return Listener (this, &callbacks);                   \
128 }
129
130 #define GET_LISTENER(proc) proc ## _listener ()
131
132 #define DECLARE_LISTENER(name)                          \
133   inline void name (SCM);                               \
134   static void name ## _callback (void *self, SCM ev);   \
135   static void name ## _mark (void *self);               \
136   static bool name ## _is_equal (void *a, void *b);     \
137   Listener name ## _listener () const
138
139 #endif /* LISTENER_HH */