]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/listener.hh
e0827f8786dc372ceaee9256f159e7d1dbe0c7d5
[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
74 {
75   void *target_;
76   Listener_function_table *type_;
77 public:
78   Listener (const void *target, Listener_function_table *type);
79   Listener (Listener const &other);
80   Listener ();
81
82   void listen (SCM ev) const;
83
84   bool operator == (Listener const &other) const
85   {
86     return type_ == other.type_
87            && (*type_->equal_callback) ((void *) target_, (void *) other.target_);
88   }
89
90   DECLARE_SIMPLE_SMOBS (Listener);
91 };
92 DECLARE_UNSMOB (Listener, listener);
93
94 #define IMPLEMENT_LISTENER(cl, method)                  \
95 void                                                    \
96 cl :: method ## _callback (void *self, SCM ev)          \
97 {                                                       \
98   cl *s = (cl *)self;                                   \
99   s->method (ev);                                       \
100 }                                                       \
101 void                                                    \
102 cl :: method ## _mark (void *self)                      \
103 {                                                       \
104   cl *s = (cl *)self;                                   \
105   scm_gc_mark (s->self_scm ());                         \
106 }                                                       \
107 bool                                                    \
108 cl :: method ## _is_equal (void *a, void *b)            \
109 {                                                       \
110   return a == b;                                        \
111 }                                                       \
112 Listener                                                \
113 cl :: method ## _listener () const                      \
114 {                                                       \
115   static Listener_function_table callbacks;             \
116   callbacks.listen_callback = &cl::method ## _callback; \
117   callbacks.mark_callback = &cl::method ## _mark;       \
118   callbacks.equal_callback = &cl::method ## _is_equal;  \
119   return Listener (this, &callbacks);                   \
120 }
121
122 #define GET_LISTENER(proc) proc ## _listener ()
123
124 #define DECLARE_LISTENER(name)                          \
125   inline void name (SCM);                               \
126   static void name ## _callback (void *self, SCM ev);   \
127   static void name ## _mark (void *self);               \
128   static bool name ## _is_equal (void *a, void *b);     \
129   Listener name ## _listener () const
130
131 #endif /* LISTENER_HH */