]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/listener.hh
2dfdc0c9f8da4865fbb279cf554d57c838a9b089
[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     DECLARE_LISTENER (method);
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   IMPLEMENT_LISTENER (Foo, method)
42   void method (SCM e)
43   {
44     write ("Foo hears an event!");
45   }
46
47   - Extract a listener using GET_LISTENER (Foo->method)
48   - Register the method to the dispatcher using Dispatcher::register
49
50   Example:
51
52   Foo *foo = (...);
53   Stream_distributor *d = (...);
54   Listener l = GET_LISTENER (foo->method);
55   d->register_listener (l, "EventClass");
56
57   Whenever d hears a stream-event ev of class "EventClass",
58   the implemented procedure is called.
59
60   Limitations:
61   - DECLARE_LISTENER currently only works inside smob classes.
62 */
63
64 #include "smobs.hh"
65
66 typedef struct
67 {
68   void (*listen_callback) (void *, SCM);
69   void (*mark_callback) (void *);
70   bool (*equal_callback) (void *, void *);
71 } Listener_function_table;
72
73 class Listener : public Simple_smob<Listener>
74 {
75 public:
76   static SCM equal_p (SCM, SCM);
77   static int print_smob (SCM, SCM, scm_print_state *);
78   SCM mark_smob ();
79   static const char type_p_name_[];
80 private:
81   void *target_;
82   Listener_function_table *type_;
83 public:
84   Listener (const void *target, Listener_function_table *type);
85   Listener (Listener const &other);
86   Listener ();
87
88   void listen (SCM ev) const;
89
90   bool operator == (Listener const &other) const
91   {
92     return type_ == other.type_
93            && (*type_->equal_callback) ((void *) target_, (void *) other.target_);
94   }
95
96 };
97
98 #define IMPLEMENT_LISTENER(cl, method)                  \
99 void                                                    \
100 cl :: method ## _callback (void *self, SCM ev)          \
101 {                                                       \
102   cl *s = (cl *)self;                                   \
103   s->method (ev);                                       \
104 }                                                       \
105 void                                                    \
106 cl :: method ## _mark (void *self)                      \
107 {                                                       \
108   cl *s = (cl *)self;                                   \
109   scm_gc_mark (s->self_scm ());                         \
110 }                                                       \
111 bool                                                    \
112 cl :: method ## _is_equal (void *a, void *b)            \
113 {                                                       \
114   return a == b;                                        \
115 }                                                       \
116 Listener                                                \
117 cl :: method ## _listener () const                      \
118 {                                                       \
119   static Listener_function_table callbacks;             \
120   callbacks.listen_callback = &cl::method ## _callback; \
121   callbacks.mark_callback = &cl::method ## _mark;       \
122   callbacks.equal_callback = &cl::method ## _is_equal;  \
123   return Listener (this, &callbacks);                   \
124 }
125
126 #define GET_LISTENER(proc) proc ## _listener ()
127
128 #define DECLARE_LISTENER(name)                          \
129   inline void name (SCM);                               \
130   static void name ## _callback (void *self, SCM ev);   \
131   static void name ## _mark (void *self);               \
132   static bool name ## _is_equal (void *a, void *b);     \
133   Listener name ## _listener () const
134
135 #endif /* LISTENER_HH */